There has been a flurry of discussion about how to teach TDD, sparked off by a recent post from Justin Searls. In it he lists a number of failures that range from “Encouraging costly Extract refactors” to “Making a mess with mocks” all of which distract attention from the concept that “TDD’s primary benefit is to improve the design of our code”. He concludes by suggesting that once you have written a failing test, rather than get-to-green in the simplest way possible you should “intentionally defer writing any implementation logic! Instead, break down the problem by dreaming up all of the objects you wish you had at your disposal”. In essence, design the elements of the solution while the first test is still red.
It’s an interesting post that raises a number of issues, but for me its value lies chiefly in opening the subject up for debate. The introduction is particularly pertinent – just setting a class a bundle of katas to do does not, of itself, encourage learning. The pains experienced while doing the exercise need to be teased out, discussed and have alternative approaches described. If you don’t hear the penny drop, then it hasn’t dropped.
Pitching in with characteristic vigour and brimstone came Uncle Bob with a robust rebuttal containing both heat and light (though some have been put off by the heat and never got to the light). Bob makes some good points regarding the fallacy of writing tests around extracted classes, the tool support for extract refactoring and the central place of refactoring in the Red-Green-Refactor cycle.
By the conclusion, however, Bob has switched tack. He states that while refactorings are cheap within architectural boundaries, they are expensive across them. Whether he’s right or wrong on this point* is of no concern because now he’s addressing the wrong question. The question at hand is “how is it best to teach TDD?” and it was taken up in a short Twitter exchange between me, Kevlin Henney and Mike Long.
Mike, being hard-core, says that he teaches TDD by “start[ing] with writing the test framework. Start from assert and up.” There’s much more to discover about this approach, and it’s certainly reminiscent of how Kent Beck learns a new language (by reimplementing xUnit).
Kevlin, in an e-mail, is more discursive. He works with a mixture of prepared material, discussions, instructor-led demonstrations and learning exercises. There are katas in the material, but there’s lots of interaction to draw out the key points and really get them to stick.
In my TDD training, I start by focusing on fundamental unit testing practices. The key word here is ‘fundamental’. TDD is unit testing++, so you need to have a firm grasp of what a good unit test looks like. We work through a series of simple bank account examples (in pairs, using Cyber-Dojo of course) that bring out the 6 essential properties of unit testing. I then use an example (based on an idea of Rob Chatley‘s) to introduce test doubles before moving into one of my own legacy code exercises. In-between I use a couple of the katas that ship with Cyber-Dojo – usually LcdDigits and PrintDiamond – to get a more varied domain experience.
There are lots of ways to teach TDD and Justin Searls has certainly identified one way of doing it sub-optimally. I have to disagree with his conclusion that the fix for this is to defer implementation till after the solution design is fully sketched out. At the opposite end of the spectrum is Keith Braithwaite‘s “TDD as if you meant it” which is an exercise you can (and should) try at home.
In my opinion, the success of any training is dependent on the trainer – the material is of secondary importance. So if you decide that some TDD training is for you, remember to think about who is training you, not just how long the course is and how much it costs.
* Grady Booch once said: “All architecture is design but not all design is architecture. Architecture represents the significant design decisions that shape a system, where significant is measured by cost of change.” Steve Tooke pointed me to an old post by Nat Pryce, which hints at a different trade off between change and cost. After all, when was the last time you were perfectly happy with an ‘architectural’ decision that was made more than a week ago by somebody else?