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.