Test-Driven Development has a distinguished history. Its future is in doubt, claims a provocative blog post, “TDD is dead. Long live testing.” by David Heinemeier Hansson (DHH), best known as the creator of the Rails framework.
TDD has been around for a little more than a decade, and was pioneered by Kent Beck. It’s an agile technique that says, basically, you should start by thinking through the requirements for your code; write very simple unit tests that would validate the functionality of your code; and then actually write the code. Programmers should refuse to write code until there is a way of testing that code. This ensures, according to the principles of TDD, that they are writing the appropriate code and it won’t break anything.
For a good introduction to TDD, see Scott Ambler’s “Introduction to Test Driven Development (TDD).” At the end of the essay, Scott summarizes TDD as:
Test-driven development (TDD) is a development technique where you must first write a test that fails before you write new functional code. TDD is being quickly adopted by agile software developers for development of application source code and is even being adopted by Agile DBAs for database development. TDD should be seen as complementary to Agile Model Driven Development (AMDD) approaches and the two can and should be used together. TDD does not replace traditional testing, instead it defines a proven way to ensure effective unit testing. A side effect of TDD is that the resulting tests are working examples for invoking the code, thereby providing a working specification for the code. My experience is that TDD works incredibly well in practice and it is something that all software developers should consider adopting.
So, what’s wrong with TDD? According to DHH’s post, it’s the small-scale nature of the testing:
The current fanatical TDD experience leads to a primary focus on the unit tests, because those are the tests capable of driving the code design (the original justification for test-first).
I don’t think that’s healthy. Test-first units lead to an overly complex web of intermediary objects and indirection in order to avoid doing anything that’s “slow.” Like hitting the database. Or file IO. Or going through the browser to test the whole system. It’s given birth to some truly horrendous monstrosities of architecture. A dense jungle of service objects, command patterns, and worse.
#!Kent Beck, one of the biggest boosters of Test-Driven Development, isn’t going down without a fight, though. As he writes in his post, “RIP TDD”:
I’m sad, not because I rescued it from the scrapheap of history in the first place, but because now I need to hire new techniques to help me solve many of my problems during programming.
Kent then writes about the many sorts of errors that TDD can help developers avoid, from over-engineering to API feedback, from logic errors to failing to separate interfaces from implementation.
Also defending TDD is Gary Bernhardt. In his blog post, “TDD, Straw Men, and Rhetoric,” Gary points out that”
TDD is useful and test isolation is useful, but they both involve making trade-offs. Unfortunately, doing them 100% of the time seems to be the best way to learn what those trade-offs are, and that can temporarily lead beginners toward extremism. TDD and isolation both break down in some situations, and learning to detect those situations in advance takes a lot of time. This is true of advanced techniques in any discipline, programming or otherwise. That is the honest, non-exaggerated, no-lies-involved truth.
My own view: DHH makes some interesting points, but hasn’t dealt a knockdown blow to TDD. His main criticism is that TDD focuses on unit tests, and not with communication with external systems or live data. That’s true. Nobody says that TDD’s unit tests should be the only tests; acceptance testing should be an integral part of the development process, whether or not the team is using TDD.
What do you think? Write me at alan@camdenassociates.com.
Alan Zeichick, founding editor of SD Times, is principal analyst of Camden Associates.