The Pieces Premise says, "To get the whole thing to do what you want, start by getting each piece of it to do what you want. It’s one of the basic underpinning of microtest TDD.
It’s a hard time out there for those working on social change. I want you to know how much what you’re doing means to me. Geekery is respite for me. But I see you, and I see how hard you’re trying.
Stay safe, stay strong, stay angry, stay kind. I am proud of you.
The idea behind the pieces premise is actually pretty straightforward. All programs are divided into pieces, separate parts, each of which performs some behavior the program needs.
If the pieces don’t work, the whole won’t work.
I have seen a lot of struggling TDD efforts in my time. A great many of them start off well and end poorly, and it’s very often because the Pieces Premise is not sufficiently understood by the would-be practitioners.
Imagine a class. (Or a function, or a subroutine, or a module, or whatever level of decomposition you use in your environment.) Let’s call it S, for "Simple". Its guts use only basic logic and primitives from your language.
Classes like this are what we start nearly all first-time TDD’ers on. You write a test, you make it pass, you design it optimally. Rinse, lather, repeat. And when you do this, I’ll be damned, you find that TDD is pretty cool.
After you do this a few times, you’re feeling pretty good about the enterprise. The tests are fast, easy to write, precise, informative, and they make a great backstop against which to change branching logic, which is, after all, the fundamental act of programming.
Now step it up, and imagine two classes, B for "Boss", and E for "Employee". And E is really just another class like S. But B? B does part of its work by using E, as bosses do, giving orders, getting results, and then applying its own logic to it.
B *depends" on E.
And now, as soon as dependency enters the picture, we take one step out of the shallows of that class S, and we drop right off into the deep end of TDD.
Dependency raises a host of questions, each with lots of answers, and how we decide to handle all this is at the absolute heart of successful TDD.
By far the most "natural" response to this situation: Ignore altogether the fact that Boss uses Employee. Write new tests against Boss, incorporating all of Boss’s work and all of Employee’s work.
And here’s the thing: down that road lies a very great deal of owwie.
Why? Well. To put it at its simplest, real programs don’t have just two parts, but hundreds or thousands. There are Employee classes, but there are also Bosses, Grandbosses, Greatgrandbosses, and so on, up until, inevitably, the capo tutti di capi: a boss of bosses.
If we follow that natural strategy, we’re going to test the Capo, ignoring the hundreds or thousands of dependencies. The consequences of this are multiple, and I usually characterize them as varieties of "awkwardness".
Define "awkward" as anything that makes us not want to read, write, run, or debug our tests. Testing the Capo while pretending that its subordinates don’t exist nearly always presents myriad forms of awkwardness. Here’s a few examples.
Capos start programs, and starting them up is often quite expensive in terms of raw clock time. The slower my tests, the less often I want to run them.
All the subordinates a Capo uses in a particular case have to be set up in just the way that triggers that case. Setup is a prelude to the actual test, and the harder that setup is to write, the less often I want to write them.
When a Capo’s "natural" test fails, the problem might be occurring in any one of its subordinates, or in their subordinates, leaving huge interpretive awkwardness. The harder a test’s results are to interpret, the less they are worth to me.
Capo’s handle a staggering number of cases. The Capo’s transitive McCabe complexity is exponentially larger than that of any of its subordinates. We’re asking ourselves to write millions of tests, and in the real market, that’s not ever going to happen.
Yikes! That’s hella potential awkwardness, and I didn’t even list all the possibile varieties yet.
If TDD is really going to work, we’re going to have to resolve this dependency question.
How? How are we going to get the benefits we dug so much from TDD in the Simple class, but apply them broadly in a world of myriad dependencies?
The answer isn’t an answer, it’s a whole bunch of answers, and we’ll have to choose among them on a case-by-case basis. No chance we can cover all of this in one muse. But let me list out a handful of resolutions, and maybe we’ll do in-depth considerations in coming days.
- Take the natural case anyway. When it was just Boss & Employee, the potential harm from awkwardnesses was barely visible. That means that sometimes, that’s the simplest thing that’ll do the trick.
- Convert a Boss to a CocktailsHost — only responsibility is to get the guests in the door — or a Facade only responsibility is to do one-liner delegation calls to its subordinates.
- Make Bosses use the results of their subordinates rather than the subordinates themselves. In refactor-ese, this is usually expressed as "Replace Supplier With Supplies".
- Hand Bosses subordinate interfaces to do their work, rather than giving them the right to choose their own. This opens us to the ability to do faking: giving them subordinates whose results and interactions we fully know going in.
There are lots of subtleties to all this, and to put it together we’re going to lean on the other four premises: Steering, Judgment, Correlation, and Value. I’ll be reviewing those soon, too.
To close today, I want to give you two more thoughts on all this.
First: notice that word "start".
We say start by getting each piece to do what you want. You can have pieces that do exactly what you wanted, and combine them in ways to make a program that isn’t exactly what you wanted.
I know this, because I’ve done it many times. 🙂
Getting the pieces assembled correctly has its own challenges. The pieces premise only points out that assembling broken pieces is even harder than assembling "working" ones.
Second: don’t be daunted by all of this seeming complication.
There are a lot of tricks to learn to master TDD, but the truth is that each individual trick is actually pretty easy to learn and grasp.
You really can get the buzz you got off TDD’ing Simple when you start TDD’ing great mobster families of hundreds or thousands of objects. Like nearly all worthwhile skills, you grow it a piece at a time, and what seems daunting now will seem laughably easy tomorrow.
"To get the whole thing to do exactly what you want, start by getting each piece of it to do exactly what you want."
It’s a fundamental underpinning premise of microtest TDD, and it’s worth the time you’ll spend learning it.
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.