Continuous quality assurance through TDD

A recent conversation reminded me that there is a misconception that TDD slows you down. At the very least in the short term, because you have to write more stuff. This claim is as false as it is perfectly intuitive and logically sound at the first glance.

Worse, all of these tests are perceived as a wasted effort, because in a highly dynamic, fast moving project they may never even have a chance of preventing regression, and that's what we write tests for, isn't it? Well, not in TDD.

A design strategy

Test-driven development is meant to eliminate fear in application development

The "test" part in TDD is less relevant than the "driven development" part. It's about having a force guiding your code towards quality, rather than catching regressions ex post facto. Frankly, I'm so used to thinking of TDD as a design strategy that I sometimes call it "test driven design" instead of "test driven development" 🤷‍♂️.

It's a declarative approach to programming. It forces you to first think of "what" and "why" before you can move on to "how". It helps you take small, well understood steps and supports "coding for deletion". You write tiny little bits of code, each of which serves a single, well-defined purpose. Solves a problem stated without conjunctions. You get them to fully operational state very quickly, and can discard or replace them with little effort and negligible sunken cost. The test is there to help you keep your code small and working continuously, so you can learn about your misunderstandings quicker.

Which is really cool, if you think about it, because it saves you from writing needless code. If you expand (and you should) into ATDD, you get even more of that. It means you get more informed decisions, more feedback from valuable experiments, and less blind alleys of "what was I thinking?".

And if you actually unintentionally change something in the process, possibly introducing a regression? A well written set of micro-tests will speed you up. It will not only show you where the problem is with laser pointer precision, but it will describe the regression to you — telling you what's broken and what effect it would have on the business and end users. Thus giving you all the information you need to fix it, without the need for a debugger. Assuming, obviously, that you've given your test names the attention they deserve.

Typing vs thinking, quality at speed

The idea that writing tests first (which is a part of TDD, but not all of it) slows you down comes from two misconceptions: "typing as a bottleneck" and "quality as a force opposing speed". Both are wrong.

I'm not sure who said that, but if typing was the bottleneck, then typists (or Starcraft players) would've replaced programmers. In programming, you only have to type well and fast enough that thoughts don't slip your mind before you put them in writing. The thoughts are what's important. As Kevlin Henney puts it, "you should remember to bring your brain to the keyboard".

Regarding quality vs speed, Allen Holub wrote that if you trade one for the other, you will end up with neither. Speed without quality is just a great way to crash and burn. Ask race drivers. So if you sacrifice quality for speed, it won't be sustainable.

Sacrificing speed for quality, on the other hand, is illusory. At least since Deming we know that quality can only be achieved by building it into the process, working in small iterations, and getting rid of waste. That makes sustainable speed an inevitable consequence of quality.

In other words, if you don't get a sustainable speed from your quality assurance process, it’s not giving you quality either. If you don't support your speed with quality, you're going to hit a wall.

The learning curve

All that said, TDD will slow you down at first, especially assuming you're used to writing imperatively — starting from IFs and FORs. That's just how it works. For most people, there's a number of mental shifts that need to happen before it becomes natural. Certainly was the case for me.

The bad news is, it's not just a matter of practice. A great teacher, Eddie Woo, said that "practice does not make perfect, practice makes habits" and this is what I see from many people attempting TDD. They jump into it without theory and deeper thought, ending up causing "test induced damage" to their code. The aforementioned mental shifts don't happen automatically, and unless you're blessed with a brain of Kent Beck, they require the right fuel to trigger them.

The resources

For me (as you may imagine if you've read any of my other posts here or my Twitter) one of the most helpful things was the study of feedback-based approaches to quality by design. There are a couple of great points of entry for that, coming from the IT angle. The best is probably the book "The Phoenix Project" by Gene Kim, which is actually a novel, so it's insanely easy to read.

It isn't really about TDD and that's kind of the point. It's a rabbit hole exposing you to the world of Lean, the Toyota Production System, PDSA, and Deming. Will it directly contribute to your understanding of TDD? No. Will it help you switch your brain to prepare it understand TDD, continuous delivery, DevOps, and agile in general, through the lens of feedback? Absolutely.

The other extremely useful resource is Kevlin Henney. And I'm deliberately not pointing you to anything specific from him, because you just can't go wrong by simply typing that name into Google or YouTube. Kevlin's role in making me a better programmer, especially by helping me bend my brain backwards to get a grip on TDD, cannot be overstated. Kevlin also has the power to instil in you a healthy dose of interest in linguistics, which is kind of helpful if your daily work involves a (programming, but nevertheless) language.

The last but not least, grab Test Driven Development and Smalltalk by Kent Beck.

Conclusion

It's not always a simple path, depending on where you start, and it's easy to get tricked into thinking that "writing tests first" is all there is to TDD. But after years of writing almost exclusively with TDD I can attest that the only way it slows you down is the good way - by giving you time to wind down and think of the code you're writing.

You should also read: