Tim Bray writes about when and how he does TDD. I think he’s exactly right when he talks about not doing TDD for green-field, beginning development. When I’m first writing a cut at a new project, I’ve got almost no idea what I’m doing. Doing TDD at this stage in the game is super expensive and really gets in the way of the exploration necessary for a new project. Having to rewrite my code as it evolves is expected but having to rewrite my code AND my tests because both were completely off base is pretty inefficient.
However, once things are pointed in the right direction, TDD is critical. It makes the incremental evolution of the software much safer, easier and efficient. Without the tests, iterating over your software is painful and liable to introduce bugs in code that was once working. TDD is at its best in the situation where the code, while not stable, is in a state of incremental evolution and not the general state of random upheaval that it is in the beginning of the project.
Like most things, pragmatism is useful. There are shades of gray around everything and saying that there is one true way makes no sense at all. TDD is useful as a tool but hammering every nail you see with it probably isn’t the best way to do things.
I’ve also started to see TDD as a tool to allow those of us who aren’t geniuses to actually produce good code. I’ve known a few true code geniuses in my career and like Picasso, their art tends to spring fully formed out of their heads. They may go back later and write tests around the code. However, they don’t need TDD to be good. For the rest of us, the incremental evolution that TDD supports and encourages helps us to write code that is functional and clean because we have to focus on the client of our software. Those of us who aren’t masters use TDD to fake it, to produce works of art that might not eventually hang on the walls of the Louvre but that make customers at art fairs all over the world reasonably happy.
0 comments on “Pragmatic TDD”
July 9, 2009 at 11:11 pm
I just watched Robert Martin’s keynote at RailsConf09 in which he extolled the virtues of TDD. (stay out of messes and work fearlessly. Go watch the video).
The work cycle he describes, “write a just enough test to fail (don’t write the whole suite), write just enough code to make the test pass (don’t write the whole app), then add another bit of test until it fails…”, would get extremely tedious, extremely fast. That’s why he elevates it to a “professional discipline”, enforced by a green rubber band around his wrist to remind him to write th’ damn tests, dammit!
I’ve attempted to use TDD on a couple of small projects, but I quickly got bogged down running back and forth between the tests and the code as each little bit of design evolved. Eventually I gave up maintaining the tests, even though I knew in my gut they would provide longer term benefit.
So now when I read your pragmatic advice, I realized you are bang on – wait until the colt’s up on its legs before you try to walk it around the corral…
However, if you postpone the TDD until the app is stickframed, you’ll face the problem of convincing yourself/your team lead/your project manager that there’s value in divert resources to writing code for tests that doesn’t actually do anything “productive”.
Have you applied this idea in practice? How did it work?
July 14, 2009 at 10:29 am
I think it’s important to get the tests going as early as possible to avoid that situation. It think there is a line in development somewhere when it becomes less expensive to start writing the tests. It’s easier to err on the side of writing tests earlier I think.
If you go too long, your own inertia starts to prevent you from starting in on actual TDD.