KISS TDD hello

published: Tue, 22-Nov-2005   |   updated: Wed, 23-Nov-2005

There's a lot of chatter in the blogosphere at the moment about Microsoft's ill-advised attempt at rewriting TDD (now generally known as MSTDD). I wrote about it myself in this post when I was feeling depressed about the uptake of TDD here at work. But now the Big Guns (tm) of the test-driven development movement have been coruscating Microsoft for what is, admittedly, a blundering attempt at calling a waterfall methodology TDD. (There's a great series of posts by Scott Bellware on his blog about all this debacle.) [Update Wed 23-Nov-2005: MSDN has now removed, er, retired, the article. 416 people had voted on it for an average score of 1.19.]

Anyway, reading Scott's posts and participating in a code review today reinforced some of my thinking about TDD.

Essentially, TDD is a methodology for exploring part of the problem space and understanding it enough to write a test and then the code to satisfy the test. It's a way of thinking about the design in small incremental chunks without getting diverted by the immensity of the problem space defined by the project's target or goal.

In other words, TDD promotes simplicity. You are encouraged to think in terms of one micro-piece of functionality from one user story, not about the whole shebang.

That’s the big problem about the MSTDD document. It promotes Big Design Up Front (BDUF): Hey big boy, design and write the class you want (of course, you know what you want), generate all the tests (cool nifty feature, eh?), stub out the class' properties and methods so that all the tests fail (throw new NotImplementedException, don'tcha know), and then write the real code so that they all pass. It's the full-blown steak dinner with the extra-cost side dishes when all you wanted to do was sample a Japanese buffet. It’s the Chevrolet truck with extended cab and four rear wheels being used instead of a bike to go and enjoy a coffee at the local Starbucks.

I consider myself to be reasonably intelligent, but BDUF scares the crap out of me. I've written thousands upon thousands of lines of code in my life, probably millions, in various different languages on many platforms. My best code has been where I took small steps, running tests as often as possible, trying to tease out the design. My worst code (in some sense) has been where I took larger steps, nay, jumps into the unknown, and just hoped that it would all work when I'd done. Oh, and of course that testing required a UI to be written first and the database to be there and...bleugh.

I just know that I'm going to get something wrong in my Big Design. And when I do, changing it is going to be horrendous. I've just come off a project where we essentially tried to harden and fix a BDUF subsystem. Needless to say we were time-constrained and only scratched the surface of its problems.

That's today's lesson in a way: Keep It Simple and Stupid (KISS). Functionality is built up using TDD from simple (stupid) classes in certain well defined patterns. And always with the protection of those unit tests. (By the way, by stupid I mean that the code and/or classes don't try and be clever, don’t try to do several things instead of just one, or don’t try to embrace complexity. In essence, you should be able to understand what the code does by reading it.)

Profiling the code is made easier in this scenario since TDD encourages the development of small classes and small methods, which makes bottlenecks easier to understand (miles better than saying "this 500-line method is my bottleneck, but where do I start?"), and easier to refactor (well, heck, you're so used to refactoring anyway, so changing the class model to make it faster holds no terrors, and, double heck, you have those unit tests, remember?).

There's another aspect to this as well. Personally I don't particularly like writing original code. I prefer tweaking. In other words, I love refactoring. Teasing out elegant code and classes? Great. Identifying code duplication and removing it? Brilliant. Seeing a possibility for another class and extracting it? Priceless. TDD enables me to write simple original code and then polish it. It's like cutting a facet on a diamond and then buffing it. It's nothing like taking a ball of clay and then fashioning it into a pot and then firing it, only to discover that the lid doesn't fit.

So, please ignore MSTDD. Instead, KISS TDD hello.