Twitter GitHub Facebook Instagram dirv.me

Daniel Irvine on building software

Wrong way round (part 1)

8 June 2014

Recently I’ve been exercising my test-driven development skills via a game of tic-tac-toe. I developed the game one requirement at a time. First, I created a playable API with two human players, then I created both human and computer players, followed by a console version, and finally a GUI version. Each stage was covered by tests encapsulating the requirements.

In amongst all of this awesome TDDness, something surprising happened: I layered my application the wrong way round.

Let’s take a look at how that operates.

Not-so-great design

The game starts via the Game class, which controls both the Board class, which holds the game state, and the Display class, which is the view. Looking at the play_turn method in Game:

def play_turn
  @board.play_turn
  @display.update_board
  @display.show_result if @board.game_over?
end

The problem with this approach is that any view class must at some point call back into the controller as a result of user events, resulting in a cyclic dependency. This is the Game callback shown in the diagram. For example, when the user clicks on the screen a mouse click event should be parsed and a ‘play square’ event forwarded to the Game class.

That dependency and callback mechanism is overly complex, and that’s the symptom of the “wrong way round” pattern: the code becomes complicated.

Thankfully since all my game logic was covered by tests, inverting this dependency was not exactly hard. It just required some rejigging of the Game class.

A better design

In part 2 I’ll discuss how I got myself into this predicament and why it’s a great example of why layering makes sense.

About the author

Daniel Irvine is a software craftsman at 8th Light, based in London. These days he prefers to code in Clojure and Ruby, despite having been a C++ and C# developer for the majority of his career.

For a longer bio please see danielirvine.com. To contact Daniel, send a tweet to @d_ir or use the comments section below.

Twitter GitHub Facebook Instagram dirv.me