This post is also available in Portuguese 🇧🇷.
Do you know how this statement from Robert C. Martin ends?
"The really effective part of TDD is ..."
Robert C. Martin (colloquially known as Uncle Bob), is the author of the classic Clean Code book, one of the original authors of the Agile Manifesto and a real die hard defender of TDD as a tool to improve developer productivity and code quality.
Not too long ago I read an old blog post of his where he states that the really effective part of TDD is not so much whether you write the test first and I must admit I was somewhat taken aback.
This kinda shocked me because Uncle Bob is as pro-test-first-development as it gets. He's even said on occasion that writing tests after production code is a waste of time. 😱
So what could be so important, with regards to TDD, that Uncle Bob would consider it to be more important than the order in which we write tests and production code?
The answer lies in the history of the famous 3 Laws of TDD. You've probably seen them or some version of them:
- You must write a failing test before you write any production code.
- You must not write more of a test than is sufficient to fail, or fail to compile.
- You must not write more production code than is sufficient to make the currently failing test pass.
In another of his blog posts called "The Cycles of TDD", Uncle Bob tells the story of how the 3 laws came to be as he recounts an experience he had while paring with Kent Beck, the father of Extreme programming (XP) and of TDD!
"I sat with Kent Beck in 1999 and paired with him in order to learn. What he taught me to do was certainly test first; but it involved a more fine-grained process than I’d ever seen before. He would write one line of a failing test, and then write the corresponding line of production code to make it pass. Sometimes it was slightly more than one line; but the scale he used was was very close to line by line."
"I, and many others, have written about these three laws over the years. They now appear in many different styles, formats, and injunctive statements. But the goal is always to promote the line by line granularity that I experienced while working with Kent so long ago."
I don't know if reading those phrases impacted you in any way, but when I saw them for the first time I was mind blown. This was a real AHA moment for me.
You see, when I started trying to do TDD I has always thought that I had to finish writing all the tests for the (let say) feature that I was about to implement before touching the production code.
I attribute this line of thought to the fact the I used to do Test-last Development, before trying out TDD. In other words, I used to code up the feature, doing exploratory testing all the while, and then write automated tests after the fact. So, in my head, TDD was just about inverting that order.
As a result, writing tests before the production code just sounded backwards to me. (And scared the living hell out of me.) I also see little sense in trying to complete a suite of tests without proper IntelliSense on a screen with all kinds of squiggly red lines in the IDE since the methods and properties being testing don't exist yet.
But as I drilled deeper into the study on the fundamentals of TDD, it became vividly clear how the practice is really grounded in repetitions of very small cycles of testing and implementation. In the book The Art of Agile Development (recommended by Martin Fowler), the author, James Shore, recommends working in cycles of testing and implementation no greater than 5 minutes or 5 lines of code.
If you're asking yourself what this looks like in action, I'd recommend watching these two videos: part of The Three Laws of TDD video and Tutorial: Mastering Test-Driven Development with Angular.
Since coming to all this realization I've been doing TDD almost exclusively and I've been finding the process very intuitive and fast. 😃
So let's wrap up, going back to the statement I asked you to complete at the beginning of this post and to the moment when Uncle Bob claimed that the really effective part of TDD is not so much whether you write the test first. 👀
I found it in yet another of his posts where he talks about a study that basically concludes that TDD doesn't produce higher quality code than other methods of development.
You should definitely read the whole thing some time to understand the context of the statement, but I'll sum it up for you: In the study, 58 developers where divided into 2 groups and asked to do a programming task. One group had to do TDD while the other did TLD (Test-last development). Both groups were asked to work on small chunks of the task, rather than utilize a waterfall approach. At the end of the experiment, metrics where compared and the study concludes that "TDD does not affect testing effort, software external quality, and developers’ productivity."
What do you have to say about that Uncle Bob?
In his analysis, Uncle Bob points out that the study asked the folks doing TLD to work in “small chunks”, inadvertently forcing both groupd to use the TDD process of short cycles, and writes:
"The really effective part of TDD is the size of the cycle, not so much whether you write the test first. The reason we write the tests first is that it encourages us to keep the cycles really short."
And there you have it. Thanks for the read!