Thursday, December 30, 2010

When thinking Design, think Jobs vs. Skills

I've been trying to get people to see that code should be built as layers of building blocks for some time. It's only just occurred to me how to explain another dimension of design that I see lacking most of the time in code I have to deal with.

It's what people refer to when they talk about building your language towards you domain. The idea is that you should be able to clearly concisely describe your problem domain in your language. If you can't they you end up with domain objects getting their hands dirty with implementation details.. like "how lists work in this language" or "managing back references" etc...

Here's my thought... Your building blocks should be separable into Skills and Jobs. Jobs are specific roles played by objects in your code. Skills are transferable, then include the details of how you manage to achieve things. You could reuse the skills in many different jobs.

When your domain objects are not <5 methods each with <5 lines... then see what skills your object has and factor them out.

Sometimes this will be extension methods on basic types (or lists, arrays, etc.), other times it's make a specific collection type that doesn't reference your domain, but identifies the relationship items of the collection have.

Does this make sense?
Do I need an example?
Is this just obvious?

Ok... needs an example.


I found this code on github... it's part of the Player class for a Battleships game.
   public void TakeTurnAutomated(Player otherPlayer)
        {
            bool takenShot = false;
            while (!takenShot)
            {
                int row = rnd.Next(GRID_SIZE);
                int col = rnd.Next(GRID_SIZE);

                if (EnemyGrid[row][col].Type == SquareType.Unknown)
                {
                    Fire(row, col, otherPlayer);
                    takenShot = true;
                }
            }
        }
The point I was trying to make is .. the intent of this code is to fire on the first random location that is 'unknown'... so it should say that. One way would be something like this...
public void TakeTurnAutomated(Player otherPlayer)
        {   
   Fire(RandomLocations.First(IsUnknown), otherPlayer);
        }
Or this...
public void TakeTurnAutomated(Player otherPlayer)
        {
   Fire(RandomUnknownLocation, otherPlayer);
        }

private Location RandomUnknownLocation
{ 
  get{
    return EnemyGrid.UnknownLocations.SelectOneAtRandom();
  }
}

Here.. SelectOneAtRandom becomes an extension method to IEnumerable. We don't care how it selects one at random.. as long as it doesn't take too long about it. Picking an item at random is a Skill we have... we use it in the Job of selecting a random unknown location. Any clearer?

GitHub Projects