TDD-blockers are everywhere for me, even now, after twenty years of practicing it, so I still try new ways to work around them, and I don’t always find them, and I wait for next time.
A respondent had a great question, and this is a kind of "sideways" answer. The question: Given that we’re halfway through an app w/o an architecture that TDD’s well, should we start TDD now or wait for the next greenfield chance to do it right?
Let me start by telling you my current status. I’m on a small team with a modest app that’s nearly done. This is a TDD team, and a very hardcore and experienced one. We’re not in any way noobs, and we’re true believers that TDD makes us go faster. Different parts of the app have different levels of TDD-nature. Parts of it are exquisitely microtested. Parts of it are clunkily so. Parts of it are not at all tested, except by ourselves and our victims in live runs.
So. What gives, eh? Bunch of hardcore TDD’ers, a greenfield app, nearly a year of work, why on earth isn’t this thing perfectly and uniformly TDD’d? I’d say it comes down to two issues: a combination of ordinary human frailty and anti-testable component design. Let’s look at those, then look at what we try to do about it, and finally look at the cost of where our efforts have failed, and why we keep trying.
The human frailty comes down to this: I am a successful working professional software developer. I was that for twenty years before I started TDD. If you put those two facts together, and if you’ve been following these streams at all, you know three things about me.
- I am obsessed w/delivering a steady stream of user-value throughout development. The stuff I put out about sociotechnicality hits right here: you don’t get to be any good at pro software development w/o being good at making AND showing AND capitalizing progress as you go.
- I know a lot of ways to write code. They include TDD, and TDD is always my first approach because it makes me go faster. But they also include all the variant techniques I used in the twenty years before I learned TDD.
- I don’t know the right answer when I start. The only way to know the right answer is to have already solved the problem, and they don’t pay me to solve problems they’ve already solved. I am constantly improvising, learning, guessing. I am a specialist at making shit up.
All of that adds up to the ordinary human frailty. I sometimes ship code too soon. I sometimes can’t figure out how to use TDD effectively. I sometimes have to take several swings before I hit the ball. I sometimes strike out. I sometimes forge on anyway. The second issue: there are often critical components of apps that are not made to ever support a TDD discipline. When an app we’re writing relies centrally on them, finding a TDD way to use them is often a problem that’s bigger than the app itself.
There’s really no such thing as "greenfield" in pro software development, outside of microcode for new CPU’s. Every app we write, in JS, in Java, in Ruby, in FP languages, every whole app depends on hundreds or even thousands of modules of code that were written before the app. Fortunately, much of that code is TDD-indifferent. That is, it’s usable by us whether or not we’re TDD’ing. The string library in your favorite environment is an example of that.
Some of it is not. If you follow me for TDD reasons, you know that a key premise I accept is "steerability". It is that tests & testabilitiy should be first-class participants in design. If they’re not, it’s all to easy to build subsystems that aren’t TDD-able. An example is JavaFx — or frankly any native UI framework I’ve ever used in my life — is extraordinarily difficult to microtest. It doesn’t expose the right things in the right place. It’s inherently multi-threaded. It has necessary but horrific hacks for cross-platform needs.
So that’s why these hardcore TDD’ers don’t have everything in their shipping app as fully and richly microtested as everything else. It’s just ordinary human frailty and the usage of central TDD-antagonistic components.
What do about this? We don’t go gentle into that good night. We use a lot of the techniques our agility gives us to aim at variant approaches that simultaneously address our frailty and enable TDD near the un-TDD-able.
The list of things we do about this is really the list of practices and attitudes I call the modern synthesis. It’s our whole approach, including CI/CD, TDD itself, our tools, our pairing, our retros, our safety, our fondness, our inside-the-team value-definer, and so on. Interestingly, the sameness in our thinking helps us not give up. The differences in our thinking helps us come up with ideas we haven’t tried.
It’s really rather cool, and it’s why I fell for this movement in the first place, and why I still advocate it.
In just one tweet: what’s it costing us, those parts we haven’t been able to TDD effectively? It’s costing us so much time and energy and spirit. WE HATE IT SO MUCH. Without TDD, we creep. Every fix is a break. Every attempt is running the whole app. Every fail is unreplicable.
I started by saying this is a sideways answer to the question: "Given we’re halfway through our non-TDD’d app, should we start adopting TDD now or wait for the next greenfield?" The oblique story I’m telling tells you the answer: start right now.
🙂 I guess it’s not as sideways as I thought, yeah?
If you start TDD today, midstream in a non-TDD development effort, you will be repeatedly hampered by normal human frailty and TDD-antagonistic components, including many that you wrote yourself.
If you start TDD "next time", you will be repeatedly hampered by normal human frailty and TDD-antagonistic components, including many that you wrote yourself.
TDD doesn’t "drop in" and it doesn’t "overlay" on non-TDD development. Over time, it changes everything. Both of those clauses are important: "Over time", and "it changes everything".
TDD, and really I mean by that all of the modern synthesis, isn’t a place you get to. It’s a — I am not a zen monk — it’s a way of being. A style of collaboration, a belt of tools, a way to see.
(It’s a Weltanschauung. a word I use in preference to "worldview" precisely to jar you into looking up the idea, and specifically that part of the idea that has to do with conscious agency and it’s lack.)
All the words we use to try to describe it just plain don’t.
They hint, they flavor, the sometimes open people up, all good things. But the only way you’re going to learn what it’s like is to slowly grow your way into it by doing it as often as you can. A lot of the bumps you’ll run into are ones others have tackled. So be sure to ask out loud when you see them. Ask me, or ask my many coaching friends, or ask the internet. Some of the bumps, the only answer is to go around them. Some of the bumps we don’t have an answer yet.
But I say go for it. It’s great fun. I’ve been doing it for twenty years, and I’m happy to do it for another twenty.
Thanks, again, for the great question. It gave me a lot of inspiration, and I hope I shared some of it back.