Friday, October 23, 2009

Don't Architect, Refactor

The test-driven development mantra is "red, green, refactor," but we far too often let other things creep into the process.  One of these things is domain knowledge.


Back in February, Gojko Adzik described his experience with Keith Braithwaite's "TDD as if you meant it" exercise. He was to TDD whether a stone in the game of Go could be taken, or not.  In the game of Go, each piece is placed on a grid and can be taken if it is surrounded by only one liberty  (i.e. free space) in any of the four cardinal directions.

His first test was to identify stones with two corners covered as having two liberties.  Yet, despite that, and armed with additional domain knowledge, his test started out like this:

GoGrid grid=new GoGrid(3,3);

See it?  Yeah, the first and only line.  It's a domain leak. And it's not just Gojko -- I do it all the time, inadvertently of course. Rather than starting off with the simplest thing that could possibly work, we have a tendency to inject domain knowledge into our code. Suddenly we find that we must create a few classes rather than a few short lines of code.  We've made our job harder and started forcing a design that didn't exist nor evolve from the code.  Our leaky domain knowledge introduces untested design, BDUF, but on a smaller, slightly less turgid scale.

With TDD,  the design is supposed to evolve, yet I often find myself saying, "this is easy to code, but...."  And the but kills me, it's usually something describing a design or architecture problem that I don't know how I'm going to solve, so I sit there thinking, and thinking, and thinking.

"Stop! Don't architect, refactor," I must tell myself. That is, I need to implement what I know, worrying very little about the design.  Writing the initial code isn't about having the best, most-pure design the first time.  The refactoring step is about cleaning up the design.  It's also been said this way, "Make it work. Make it right. Make it fast."

2 comments:

  1. Hi Kaleb,
    It's very, very hard not to rush ahead with classes that one "obviously" needs, and the more experienced the programmer is the more difficult it is. Every time I catch myself doing that I find that when I roll back and address the problem again using stricter TDD I learn something interesting about the problem and the solution spaces. But it is tough. Pairing helps

    ReplyDelete
  2. You're scaring me Keith... I was really hoping that it was going to get easier with time, rather than difficult, though I think I can definitely see what you mean.

    It's becoming fairly easy to look at work underway and say something like, "Well we can use a builder here, place a façade there, and then leverage a couple of strategy classes and we'll have a nice reusable framework for the rest of the project."

    Of course, if that's what I end up doing, I've likely written 66% more code than I needed to.

    Thanks for the great reminder to TDD "is if you meant it."

    ReplyDelete