Part of 9 in the series
We talked about five underplayed tdd premises before, here’s a video & transcript. over the next couple of weeks, I’d like to take a little time and go over each of them in more depth.
Today, let’s start with the money premise.
The money premise says: "we’re in this for the money." TDD is fundamentally about making money. In software, we make make money by Shipping More Value Faster (SMVF).
I’ve been doing, teaching, writing, arguing, and coaching TDD for almost 20 years. In that time i’ve heard one helluva lot of reasons why TDD could never get us to SMVF. I won’t enumerate them all, but instead want to pick on just one, cuz it’s a great intro to the money premise.
"On a great day, I might write 1000 lines of production code. TDD suggests that, instead, I write ~500 lines of production code, and ~500 lines of test code. TDD won’t make SMVF cuz I won’t write as much V in a day. QED." (yes, yes, never mind that LOC is not a great measure of value. It’ll do for the moment as a temporary stand-in. Let’s just take this argument as legitimate in spirit.) this argument is based in a notion that the thing that takes up one’s great day is writing code. That the limit of 1000 lines, in other words, is a limit because that’s all the entering code one could do in a day. I would contend that this is not so. We say, "typing is not the bottleneck." what that means is that the hard part isn’t writing code, it’s knowing what code to write. I am not stuck at a 1000 lines in a (great) day because I can only enter that many lines, but because I can only think of that many lines to enter.
The money premise says we’re in this for the money, for shipping more value faster, and it’s explicitly claiming that TDD helps my think of lines to enter, and it helps me do that dramatically, more than enough to make up for its cost.
So how does TDD fulfill this promise? Let me count the ways…
1) TDD narrows mental scope, focusing our thoughts laser-like on very small problems in very limited contexts. Each test we roll is quite small, micro, even. Its solution is just one enhancement — one little value-add — and we’d expect it to be solved in a matter of minutes. It normally involves far fewer than half-a-dozen mental entities, well within the thinking knee. The tests are written interactively, a little test, a little code, a little test, a little code. Tho the final scope may be quite substantial, the local context is BY INTENT AND DESIGN a very small context.
2) TDD tests explicitly capture the intent of the code they exercise and express it an alternative form, cushioning and supporting exactly the hardest part of coding: understanding the why of a chunk of code. In multi-coder environments, this is an obvious benefit, but anyone who’s been coding for longer than a year will certainly recognize the experience of not knowing why even your own code was written the way it is. TDD tests are a kind of analogue to comments — except unlike comments, they are far less likely to mislead (or lie), because they are executable comments.
3) TDD tests provide highly focused debug sessions, greatly reducing one of the most time-consuming tasks coders undertake in their daily lives. When we see a bug in TDD, we write tests, often large-scale, evolving steadily smaller as we investigate, focusing and refining our attention and our tests as we go, until our list of possible culprits is narrow enough to truly find the flaw. We are typically working with twin tests, one at larger scale, one at smaller. We’re looking for both tests to be consistently red, proving they’re testing the same thing. The tests provide us with ready automated repeatability, and that makes our debugs far less painful.
4) The interactivity of TDD testing builds profluence, steadily building confidence & authority as we proceed. When HBR did it’s massive diary-study of worker motivation, a key (new to many) insight was that workers like very much to feel progress as they work. The steady accretion of microtests during the work day provides a concrete (executable) progress meter. Profluence — "forward-flowing" — is a major force in our ability to function at our highest levels of performance, and TDD provides a form of it.
5) That same accretion of tests adds rhythm to the coding process, and the steady pulse of tension & release steadies and soothes the key actor in the act of coding: the human mind. Writing a test, what TDD’ers call "getting to red", creates a tension in the writer. Passing that test ("getting to green"), releases that tension in a powerful rewarding way. Refactoring the result, or "getting to gold", extends the release & builds juice to start the next beat. The steady beat of TDD greatly enhances our ability to code all day.
6) TDD flags value-toggling, where adding value B breaks value A, and restoring value A breaks value B, a common situation once programs get large enough to not fit in the head at one time. The TDD tests persist. What we tested yesterday is still being tested today. It can’t quietly fail. TDD doesn’t solve such problems, but often enough the problem isn’t solving them, it’s noticing them in the first place. TDD does the noticing for you.
7) TDD quickly reveals the smple human-computer language mismatches, the cases where u meant X and the computer heard Y, the source of the overwhelming majority of shipping defects. You know the kind of mismatch i’m talking about: you meant to say "if(a!=b)" but you mumbled "if(a==b)". Computers have no damned sense, and they can only do exactly what you said, not what you meant. Off-by-one, inverted logic, parameter misordering, unreached code, these form surely >80% of bugs. All of these are revealed much sooner when we have microtests exercising our code. That translates directly into far greater value being shipped.
8) TDD is a remarkable proxy for the abstract principles we call "good design", because the attributes of good design are the very attributes required by the TDD approach. Loose coupling, dependency inversion, smaller units, interface segregation, immutability, all of these ideas don’t just make designs better, they make testing easier. The natural outcome of efficient TDD is superior design. Return to the beginning. The money premise says that TDD is fundamentally about Shipping More Value Faster, which is how we make money out of software.
The hard part of coding isn’t entering the code, it’s knowing what to enter, knowing it works, knowing what impact it has, knowing why to enter it. TDD works money magic by directly easing these varied tasks of knowing. The Money Premise: We’re in TDD for the money.