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.
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."
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.
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.
Thanks for reading. Want more? Do me two solids:
1) Subscribe. It's free, spam-free, and comes in full text or audio. https://geepawhill.org/subscribe
2) Embrace change, enact change, support change, in and out of the geek trades. Black lives matter. It ain't over, it's barely started.
1) Subscribe. It's free, spam-free, and comes in full text or audio. https://geepawhill.org/subscribe
2) Embrace change, enact change, support change, in and out of the geek trades. Black lives matter. It ain't over, it's barely started.