Agile engineering practices: time to get serious with TDD
In my previous post I mentioned that like most agile adopters, at Huddle we would describe our process of a “blend of XP and Scrum”. Expanding on that a little, I would say that Scrum has formalised the process side of agile and with a few exceptions (terminology, iteration length, and handling mid-iteration change) our agile process looks very like a Scrum implementation. XP on the other hand has much more to say about engineering practices (Continuous Integration, Test Driven Development, pair programming etc) and we draw guidance on development practices from XP.
Which brings me to the subject of this post: Test Driven Development. For me this is an essential, and often ignored, part of the deal with implementing agile development. Test driven development has many much discussed advantages, but for me there is one killer argument for TDD at is goes like this:
Agile development is about delivering production-ready code every iteration, which means writing just enough of the architectural framework to get each story done and refactoring and improving it as required with each new story. This ongoing refactoring is essential to ensure you end up with an elegant and maintainable system, and to avoid building up technical debt. Refactoring can be a risky business - it can (and should) involve moving swathes of code in to another class or method, changing method signatures, interfaces etc. How do you know that the major surgery you have just performed on your code base has not broken everything? Answer: unit tests. These alert you to what’s broken, or give you confidence that everything is good. And when is the best time to write a unit test? Before you write the code! This makes you think about requirements and test cases from the very beginning, makes sure the code you write is in fact unit testable, drives sensible design, and gives you an easy way to debug as you go. Most importantly, though, it is the time the tests are mostly likely to get written. Who can be bothered to write unit tests when you have just finished your story and it all seems to be working fine? And even if you can, how can you be sure you are testing the right things? Unit tests written after the code are generally just a box-ticking exercise, to say you did it.
So to summarise, you need to refactor constantly as the payoff for “coding for now”; you can’t refactor with confidence without good unit test coverage; the most useful time to write unit tests is before you write your code.
With this in mind, we have been using TDD on all new development work at Huddle since last autumn. That’s not to say it’s easy of course - some legacy parts of our code base are just not designed to be unit testable - but we are slowly driving up test coverage, giving us increasing confidence in our refactoring, as well a our new code.