Skip to main content

Test-Driven Development and Software Quality

Posted by johnsmart on May 26, 2008 at 7:38 PM PDT

Any Test-Driven Development practitioner will tell you, Test-Driven Development is a design strategy, not a unit-testing technique. Writing unit tests are a means, not an end. The goal is to write better quality, more reliable, and more accurate code.

I recently read a study in the IEEE Software journal ("Does Test-Driven Development Really Improve Software Design Quality", IEEE Software, March/April 2008), by David Janzen and Hossein Saiedian, that tried to establish measurable benefits of Test-Driven Development on software design quality. Now any TDD practitioner will tell you - using TDD properly tends to produce better quality code. Not just code that is tested better, but well-designed code.

This study looked at TDD as an isolated practice, independent of other agile practices. Indeed, TDD isn't limited to Agile development - you can also do TDD in more traditional development processes. Just replace the "Detailed Design -> Code -> Unit Test" cycle with "Unit Test -> Code -> Refactor".

Not suprisingly, teams that practiced TDD obtained much better code coverage statistics. But, more interestingly, the study also found that coding teams that practiced TDD tended to implement smaller, simpler solutions, with less lines of code overall, and less lines of code per method. The cyclometric complexity was also lower, which is a side-effect of simpler, more testable code. My own experience, like a lot of TDD practitioners, tends to bear these finding out. However, it is hard to come up with objective evidence, since you rarely solve exactly the same coding problem in the same conditions twice.

Testable classes tend to be more modular, configurable and flexible. My gut feeling tells me that classes coming out of a TDD approach are more loosely coupled. TDD is a nice fit for techniques such as Dependency Injection and the use of interfaces, which encourage more loosely-coupled and more flexible components. The study did not provide any hard evidence of this, however. The authors speculated that this reflected the fact that TDD developers use a "good" kind of coupling, using interfaces and abstract classes. This "good" coupling results in more flexible components, rather than more rigid applications.

So, basically, there is some objective data indicating that TDD promotes better quality code. This makes sense. When you practice Test-Driven Development, you think about how your class will be used by other classes. Go far enough and you should get to a precise user requirement - otherwise, what are you coding for? Just writing code without any thought to design or testing is just hacking. When you do traditional up-front design on paper before you code, you won't think of everything, and the original design often bears little ressemblance to the final implementation. On the other hand, writing, or at least envisaging, your unit tests helps you flesh out a clean and efficient design for your class. You can jot down UML sketches to help formalise your ideas, but there is no substitute for trying to write the code that actually uses your class.

One interesting exception is the domain model, which often lends itself well to careful up-front modelling, though even this will evolve throughout the life of the project.

Comments

It is very hard to study these issues objectively, and I would take these results with a grain of salt. To their credit, the authors are frank about various weaknesses of their research. In the industry projects, there is also the issue that the more with-it developers may well have been the ones who opted to join the TDD teams. In addition, if you look at table 1 on page 79, you will find that 5 out of 6 projects are quite small (842-2071 LOC). In the only large comparison, the test-first project has 2750 LOC and the test-last project 49,330, so it isn't clear how comparable those are.

I dont think there is any reliable study on which technic would be best for a particular software development. After designing a software product, TDD can give you more than just producing quality code. It may also reveal weaknesses of the design. Testing while developing is something I can never give up as an architect. It just helps you put out more mature and advanced designs in the next time around.

If you have steady approach/religion by implementing/designing TDD I think is useless here. If you have some specific area and very specific logic where there's a more than few classes in collaboration process then yes, TDD can help to move to the mature/reusable status.