Microtest TDD’s Steering Premise is quite simple, which may be why it sometimes meets furious opposition. It says "Tests and testability are first-class citizens in design." Let’s talk that over a little.
As is my wont, I remind you, TDD, and even geekery, aren’t really the most pressing story around us today. It’s comfort food, a chance to catch my breath.
Black lives matter. Stay safe, stay strong, stay angry, stay kind. We can change this, we’re the only thing that can.
There are, for any software problem, an infinite number of functionally correct designs. If implemented, they will work. But we don’t implement an infinite number of designs. Why not? Because though they may be functionally correct, they still don’t fit our context.
We reject designs — more often we reject individual choices in designs — for a variety of reasons: reliability, cost of hardware, poor fit to our toolset, and so on. Those reasons are the "citizens" of the design process.
And the steering premise says that one of the citizens — not a secondary or minor or ex post facto consideration — is whether that design can be tested.
To probe at it: If you brought us a functionally correct design that required our app to run on a million AWS instances, we’d casually say "no, that’s not valid." So obvious is this conclusion, that no one ever does it. Designs don’t even get that far with such an issue.
And if you brought us a functionally correct design that couldn’t be tested until it was in the field?
If we’re following the Steering Premise, it’s the same answer: "No, that’s not valid."
Why? Why do we insist that tests & testability be such a central concern in our approach?
Just recently, we talked about the differences between modern geekery and that of forty years ago, and the answer is there: the higher levels of Collaboration, Complication, and Continuity.
Modern geekery is collaborative geekery, with many hands touching each part of each shipped feature. And tests are a tremendously powerful collaborative framework.
Tests are executable & deterministic. When we get to use them as part of our collaboration, they correspondingly sidestep issues of theory — endless sprouting what-if’s — and issues of interpretation — you say "good" and I say "bad".
Don’t mistake me: tests can’t supplant direct human interaction, by no means. But they are excellent adjuncts to that interaction, allowing us to use a kind of runnable shorthand in our exchanges. It’s a startlingly powerful enhancement to our other communication techniques.
And complication: those parts used by a feature, they aren’t usually used by only that feature, but by several others. Testability lets us lock a part’s behavior to account for all the features that use it.
Consider an Account. We use it for billing. We use it for contact names. We use it for emails. We use it for association. We use it in myriad features. Testability lets us pin down each of those cases and assert that the part meets all of the responsibility placed on it.
And continuity, the long lifespan of the apps we write today. Take that part that supports multiple features, and change one of those features. Testability lets us have high confidence that a change in one feature’s part-usage does not affect another feature’s part-usage.
In brownfield development — remember how much of modern geekery is brownfield — this cross-feature confidence in parts is of enormous value. Regression bugs are far and away the most vexing problem for teams working on apps that are already fielded.
In many respects, it is the modernity of geekery that has raised tests & testability to such prominence in our designs. Collaboration, complication, and continuity are all major forces driving that change.
So, in practice, what does the steering premise really mean?
Under real-world circumstances, it’s about how we draw the lines between parts, and what we pass across those lines. Testability suggests some lines are better than others, and some passings better than others.
A typical aspect:
Not freely intertwining "our" code and "their" code. This is because framework & library code is so frequently awkward (or sometimes impossible) to t. Isolating our branching logic from their http transport increases our testability.
A second aspect:
We talked about boss & employee designs the other day. A key steerability concept is to make bosses as light as possible, essentially pure delegation to multiple employees. Why? So we can regard the boss as largely untestworthy.
In these and most cases of applying the Steering premise, our focus is on how the lines (and the passing across them) influence our ability to gain high confidence in our parts. We schmoosh those lines & that passing to get designs that are functionally correct AND testable.
The Steering Premise: Tests & testability are first-class citizens of design.
We adopt it because of huge increase in collaboration, complication, and continuity that modern geekery requires to succeed. It is a fundamental premise of TDD: we change designs to make them testable.
If you love the GeePaw Podcast, consider a monthly donation to help keep the content flowing. You can also subscribe to get weekly posts sent straight to your inbox. And to get more involved in the conversation, jump into the Camerata and start talking to other like-minded Change-Harvesters today.