What I’m talking about when I talk about TDD
First I thought TDD was about testing, then that it was about designing Now I’m convinced it’s about thinking at sustainable pace
My name is Uberto and I write tests.
I write many type of tests, unit tests, integration tests, acceptance tests, tests for performance, for design, for reliability etc.
I heard about automatic testing for the first time around 2000 and I immediately got excited about it. I also coauthored the first open source xUnit framework for Borland Delphi, my main language at the time.
At the beginning I was concentrating on the automatic validation aspect. With my tests I could increase my confidence that everything was working as expected. I used to design a new software using UML, and then start writing tests to verify each class before writing code.
Later I learned how to use the tests themselves to drive and explore the overall design. Writing tests with interfaces and mocks, before writing a single line of code, allows me to experiment and really feeling how the code would work, without wasting time with paper and diagrams. Later, while I am writing code to make tests green, I can understand the critical points of the design and to improve it before completing the first implementation.
As an aside: I still use paper and whiteboards for high level architectural diagrams, but not for class/object level design.
But recently I realised this was not the main benefit of Test Driven Development.
Let’s take a step back, and let’s imagine we have to design the implementation a new functionality. Even if it’s just writing few classes to work together, there are a lots and lots of possibilities. We can use several Design Patterns, we can use off-the-shelf libraries, we have to sort out which data structures and how to name them to reflect out domain.
But as we start writing code, our alternatives dwindle. It’s a bit like in the game of Go, where you have a lot of possibilities in the opening, a few in the middle game and then only one in the end.
But what if we end up stuck in a bad position? Different from the game of Go, writing code allows us to go back on our steps and try a different solution if we find a problem.
Going back and forth between different solutions makes very easy to forget some details along the way, realise it later and correct for that, then try it again without luck, and finally spending hours going in circles.
And here TDD really shines! We can retrace our steps, try other ways and still be safe with our test harness in place.
If I don’t use tests for design, I find myself writing code in a hurry, because I cannot keep all the details that I have in my mind for long. Instead TDD gives myself the pleasure to write code at my pace, with the ease of mind that I don’t risk to forget anything.
For complex problem I routinely try at least three different approaches. Tacking a problem from different angles, I finally feel much more confident about my solution.
If Waterfall is like expedition-style and Cowboy coding is like free climbing, TDD is like alpinism. Safe but still quick enough.
Unfortunately this is something I really struggle to communicate properly when I do courses about TDD. Even when people learn and practice TDD they mostly use it just to validate their first design idea. If it proves hard to test, well… we are prepared to write tons of mocks if necessary!
So if you are practising TDD please listen to your tests and try different solutions before committing to one. In this way you will improve your design skills every time and for what it is worth Uberto will be proud of you.
ps. maybe I should also blog about How to listen to tests, Styles of TDD and When is better not to write tests.