Skill Zero: Test Driven Development

Hello and welcome to Small Batches with me Adam Hawkins. I’m your guide to software delivery excellence. In each episode, I share a small batch of the theory and practices along the path. Topics include DevOps, lean, continuous delivery, and conversations with industry leaders. Now, let’s begin today’s episode.

I’m interviewing for open position in one of my teams. I asked one of the candidates “what are effective practices for writing unit tests?” He said “TDD”. That’s Test Driven Development, commonly practiced by the “Red-Green-Refactor” loop.
He told me how hard it was to start doing TDD, but now he can’t imagine stopping. The results are too powerful. We talked more about the challenging on-ramp to an ultimately rewarding path.
This is a common path to TDD. He described how adopting TDD changed his mental model for writing software. That right there is the inflection point. Each person who has seriously practiced TDD knows what I’m talking about. There is a clear marker in history: before TDD and after TDD.
So, in this episode, I’ll tell you why I think TDD is skill zero for software engineers.

But first, a reminder on this month’s giveaway. TDD will teach how to think about the code. A3 thinking will teach you how to think about problem-solving. That’s the outer loop that drives the inner loop. You need both.
So this month I am giving away a free copy of the seminal book on A3 thinking: Managing to Learn by John Shook.
This book showed me how to approach practical problem-solving using the A3. I’ve done by best to apply it’s wisdom. A3s hav been a game changer for me, each time leading to better outcomes and deeper problem-solving.
Go to SmallBatches.fm/107 for instructions on how to enter. Entries close at the end of the month.
Now, onto TDD.

I can talk about TDD forever. The best doorway into that conversation is seeing TDD as a waypoint on a path to software delivery excellence.
These days, I call TDD skill zero for software engineers because it’s the skill that unlocks the capabilities for software delivery excellence.
TDD unlocks continuous delivery. Continuous delivery unlocks what actually matters in software delivery. That’s fast lead times from idea, to commit, to production. This is a win-win for the entire value stream. Most importantly, the biggest win is that matter’s to the business.
More over, those faster lead times don’t come with lower quality. In fact, it’s the opposite because quality is what enables you to move quickly.
If you get this far, then you’re already ahead of the game. Though there is another level. Continuous delivery unlocks continuous deployment. Fully automated single-piece flow straight to production. That is what real flow looks like in software development. Commit to master, give it 10-15 minutes, and it’s running in production. Now, go and see.
These points are effectively the thesis behind _The DevOps Handbook_ and _Accelerate_. The faster the flow, the faster the feedback, the faster the learning. Working software provides value in production, so the faster we get there—that’s TDD & continuous delivery, the faster we collect feedback on value provided, the faster we can learn and experiment.
I did not fully appreciate this thesis until I gained experience in two areas. The first is working in teams and systems that were not practicing TDD and were not close to continuous delivery, let alone continuous deployment. Second is leading teams and working in management.
Let’s focus on the second. First, a simplified and somewhat reductionist view on management. Management primarily cares about delivery, then the general health of the team. Management wants stable—thus predictable-delivery on business outcomes.
Stable delivery comes from software that is easily, quickly, and safely changed. TDD creates that by building the test suite that supports rabid and safe software evolution. The opposite feeling of long lead times, complex coordination of poorly coupled systems, new bugs created out of poorly tested software, and long rewrites are like nails on a chalkboard to management.
That doves tails into the first point on how teams work. Shipping valuable software to production is the heartbeat of all software teams. The stronger the heartbeat, enter TDD, continuous delivery, and continuous deployment, the healthier the team.
Teams without a strong heartbeat are simply less happy. Small changes take far longer than they need too. Complex and poorly coupled systems require manual testing. Refactors, the kaizen in daily work, becomes challenging and even off-putting. Tech debt accumulates. The debt becomes more difficult to pay off without the safety net of strong test suite. I’ve spent time on both ends of the spectrum. Teams practicing TDD are happier, more confident, and faster than the alternatives.
This is the segue into systems thinking.
Recall the previous episode on systems thinking. There are two types of feedback loops: balancing and reinforcing. Reinforcing is like the snowball effect; more leads to more. Balancing does what it says on the tin. They’re a counterforce like brakes on a moving car where the driver aims for equilibrium. Sometimes equilibrium may be a full stop, sometimes it’s just slower.
TDD can be a reinforcing and balancing feedback loop to the system.
TDD balances out the natural technical decay in any software system. Here’s an example. I have a codebase backed by TDD, a robust test suite, and a continuous deployment pipeline. I know the dependencies are major versions behind with significant breakages. There has been no pull-to-date to actually _do_ the dependency upgrades. However, when there is, the plan is simple: update the dependencies, make the test suite pass. If all these preconditions were not met, then doing a major dependency upgrade could end up feeling like an unguided rewrite and less like a maintenance task.
Here’s another example.
TDD balances our poor software design. The best example is poor boundary enforcement. Code that cross more boundaries has more collaborators and less focus. That code is inherently more difficult to test. When you actually _write the test first_, you hit these issues early and often. You simply cannot shove your way through them. The design must be reworked to support the testing. Applying TDD consistently smooths out many rough edges.
That was balancing feedback loops. Now, the examples of reinforcing feedback loops.
The power is in the velocity reinforcing feedback loops. Once preconditions are there, then net-new additions to the software acquire the same benefits. More over, the net-new additions apply technical kaizen to the what was already there through the “Refactor” step. This creates the virtuous cycles of continuous improvement through the creation of new business value. New features, defect fixes, tech debt repayments, and risk reductions become increasingly easier and faster to do. This is what everyone wants.
Another example of the reinforcing feedback loop is the creation of more TDD-capable engineers.
This is where we return to the mental shift mentioned earlier that happens when practicing TDD. Engineering leadership’s key responsibility is sharing knowledge and developing the capabilities of others. Onboarding junior and new engineers to TDD–and the capabilities it unlocks like continuous delivery and continuous deployment–leads more of the same velocity, quality, and safety in the future. It demonstrates that you actually can have your cake and eat it too. That’s rare and powerful.
One facet of that mental shift is batch size control. This is my last point before closing out this episode.
Consider two points in time in the developer’s journey. Let’s call this developer Adam. Here’s the earlier point in the developer journey.
Adam doesn’t know best practices. Adam doesn’t know a lot. But, Adam knows he enjoys creating things! Adam can type words into an editor and the computer does something! Words show on a screen, response comes back from a server or an animation shows. It doesn’t matter what it is. It’s just cool, fun, and Adam is building it.
So off he goes. Building, futzing around, and manually testing. The code just becomes _whatever_ but things still _work_. The plan is “do”. Just make the thing do whatever it’s supposed to, then check it. Commits are simple messages like “do thing”, “fix whatever”, or “new feature”. Good enough for many cases, but not truly professional.
Now let’s fast forward much later in Adam’s developer journey.
Adam pulls a new ticket from the queue and prepares for the work. Adam sees this is a large change, so he ponders a few ideas before continuing. He knows the changes cannot happen all at once, so he prepares a sequence of small incremental changes.
The strategy is any change is always the same. PDCA: Plan, Do, Check, Act guided by Red-Green-Refactor. The plan is come up with an implementation. Do: write the test, then code. Check is always the same: are the tests passing? If not, keep working, If so, refactor.
Adam does not commit to an implementation at the beginning. Instead he tries a few alternatives to converge on best fit. Experimental code is discarded with git reset commands. When Adam sees the implementation and the incremental sequence of changes, then the real work begins.
First the test, red test suite, the then code, red test suite, fix the first failure, green test suite, continue. Red-green-refactor. Commits are surgical and clearly thought out. Net-new and refactors are clearly delineated. Commits stack on top of each other directly in master. Clearly evident in Github with green checkmarks beside each one. Code is ready for production.
I call our developer Adam because it’s me. These are two way points on my journey to software delivery exellence.
The first point is early on before I had any notion of skill zero. The second point is much later after acquiring skill zero. There is no going back for me. No regressions. Only meeting the bar and helping others find it for their first time.
So, if you have not yet acquired skill zero, then acquire it. The path to skill zero is challenging and rewarding. The best part is that it’s 2024 and not 2004. There are so many great materials for learning TDD. Go read Dave Farley’s books and listen to this podcast. Go read Kent Beck’s new book “Tidy First”. Go find the materials for evolving systems guided by tests in your preferred stack.
Then, start. Start by actually writing the tests first. Make that red test suite green. Then refactor. Repeat.

Alright, that’s all for this batch.
I need your support to keep this podcast viable. I’ve setup a patreon to support this podcast and its cousin, the Software Kaizen substack. Your support ensures I can continue producing Small Batches episodes like this one and long-form written content on Software Kaizen.
Go to SmallBatches.fm/107 to a link to my patreon, the free April giveaway, and more on TDD.
I hope to have you back again for the next episode. Until then, happy testing.

Creators and Guests

Skill Zero: Test Driven Development
Broadcast by