Wednesday 30 July 2008

TDD and bottom-up vs top-down design

Recently, I got to the point in my Beaver prototype of having developed the game components (tiles and board), the scoring algorithm, and the rules for valid tile placement. However, I was struggling with where to go next. Up to that point, I'd been neck-deep in TDD, but I couldn't see a natural next step that didn't require a lot of architectural planning.

I realised that all the TDD I'd been doing — and all that I'd ever done, for that matter — had been bottom-up design. And that this sometimes made me incredibly uncomfortable with it. Often, I simply can't predict what little class or method I'm going to need next. Certainly not when I'm sat staring at unit tests.

In this particular instance, I had to take a step back and code the following, much higher-level test:

[Test]
public void PlayGame()
{
  Player playerOne = new Player(TileSet.Side.Good, new IdiotStrategy());
  Player playerTwo = new Player(TileSet.Side.Evil, new IdiotStrategy());
  Player.PairOpponents(playerOne, playerTwo);

  Board board = new Board();

  Player nextPlayer = playerOne;
  while (playerOne.InTheGame || playerTwo.InTheGame)
  {
    nextPlayer.PlayTurn(board);
    if (nextPlayer.Opponent.InTheGame)
    {
      nextPlayer = nextPlayer.Opponent;
    }
  }

  ReportScore(board);
}

As you can see, it isn't much of a test at all. There's not a single assertion in there. However, it did clear up in my head how a game would play out and what new classes I was going to need. At the time of writing the test, neither the Player class nor the IdiotStrategy class existed. And so the code flowed from my fingertips once again.

By doing a small amount of top-down design and forgetting about the legitimacy of the test, I'd broken through a mental blockage. If I ever needed it, it was yet another reminder that no single approach should be adhered to dogmatically.

So say we all. :-)

No comments: