Since starting the zombie code kill blog, a post on TDD has been on my to do list, but I found it to be a difficult topic to write on. This is because it is difficult to treat the topic in a fair and balanced way while keeping it short enough to remain an interesting read. After a while I included a short summary in my 10 Agile tips post under the tip “Practice TDD, but not before you understand what it really is and the purposes of both schools” where I give a cautious recommendation for practicing Test Driven Development.
The truth is, despite having been around for decades, TDD is still loved and hated in almost equal measure throughout the development community with countless people still swearing it is overrated or flawed. DHH’s recent blog post, TDD is dead. Long live testing has become the controversial post of the month, starting a war of words on Twitter and the wider WWW, and I’d like to take the opportunity now to expand a little on my own thoughts as well as point you to some other good posts and resources on the topic.
I do believe it is important to recognise the downsides of TDD as well as its benefits. It is even more important to understand there are still some major myths about TDD that are prevalent and lead a lot of developers to eventually conclude that it is a waste of time. I don’t have a lot of Rails experience but I am inclined to agree with Piotr Solnica’s statement:
For me practicing TDD in a rails environment is much harder than when I work on my OSS libraries. There are many reasons why TDD in Rails is just a bit harder than it could be but that’s a big, separate subject.
At the company I work at, unit testing was introduced years ago but not used that much until after teams got converted into Scrum teams and were encouraged to start doing TDD. I have seen a variety of attitudes to it and even amongst the advocates much disagreement about which techniques are better. We have a number of enterprise applications, and the one I have mainly worked with over the last year is a million lines of .NET code, about 800 database tables, 2000 stored procedures and more than 100 gigs of data. A couple of years ago, we had more Q.A. testers than developers working on it. The amount of manual regression testing on it was ridiculous and unsustainable. Live releases were just once every 3 months, and usually followed by an emergency fix despite all of the countless hours of Q.A. testing that were done.
TDD has been one technique that has helped to right some of the wrongs of the past. We now do live releases every 2 or 3 weeks, we have approximately two developers per Q.A. tester, and our rate of change is at least twice that of before. Our code coverage has been steadily increasing month on month along with the ratio of automated to manual testing. Our time to market for new high priority changes is a fraction of what it was in the old days.
However, there is clearly still a long way to go and I don’t think we have gotten everything right. If I was to do the last year over again, I would have spent more time working on integration tests and a little less time working on unit tests. I wouldn’t have spent time unit testing internal details and would have worked more on outside in testing. In Roy Osherove’s talk “Where do you start with legacy code?” he states Integration First. This is from a man best known for his book The Art of Unit Testing. You have to be pragmatic. Knowing that the system works as a whole is more important than knowing that some small units of functionality are working correctly. Ideally you want tests for all of your units as well as all of your higher level components and how the work together. But in the real world all you can do is improve little by little. Recently I have been influenced by Ian Cooper’s TDD where did it all go wrong talk and would encourage anyone who is finding TDD isn’t working for them to watch it.
So, in summary, despite the title and opening statement of DHH’s post being sensationalist, I agree with some of the points he makes. Some of the pro TDD rhetoric over the years has gotten a little silly. Calling a fellow professional “unprofessional” for their choice of one particular development/testing technique over another strikes me as a little, hypocritically unprofessional.
DHH has given Test Driven Development a good go and if he finds other practices are work better for his company then I can certainly respect that.
TDD is a practice that doesn’t come with a quick return on investment. It takes time to get to the stage where all your developers are skilled enough, and more importantly where your code base is clean enough, to be as or more productive developing solutions in a test first manner than just banging out the production code. Much like pair programming, and refactoring to SOLID, there is plenty of value to be found in the TDD practice, but you don’t necessarily want to do it 100% of the time.
Having said all of that, I can understand the frustrations of many developers because, by and large, sloppy practices are still far too prevalent in our industry. Even zombie code!
I was going to leave this picture as the conclusion to this post, but I’m going to be a little more explicit and talk a little about empiricism. Assess the risk of API changes, the skill of your development team, the attitude of your team towards TDD, how testable your existing code currently is and how many (if any) unit tests you have. How much would you need to refactor your existing code in order to be unit test friendly? How longer does your application need to be around for? Is it throwaway? What are the other automated testing options? Which is cheaper? Which are faster? By how much? What is the cost of manual testing and how much would you save by automating that work? How much would it cost to give TDD a try for a few weeks to see how it goes? If you’re already practicing it, is it working for you? If not, why not? Only once you have answered these questions can you really tell whether TDD is right for your company.
Justin Searls on the failures of Introduction to TDD.