Welcome to the latest issue of my newsletter series, ‘Test First vs Last’, where we’ll explore how the sequence of writing tests affects our minds. The full context of this series can be found in the introduction post.
Test-driven development (TDD) is often rejected due to its perceived unintuitiveness. Is there a way to make TDD more intuitive? I believe there is, and it requires us to think more about specification first, rather than testing first.
In this essay, I’ll explain why spec-first might be more intuitive than test-first. I’ll further explore why we still don’t write a spec even though it’s an intuitively small yet impactful step, with the hope that more of us will think about this in our work.
Spec first, test last
I previously wrote about how unintuitive TDD might be for some. The root of the unintuitiveness of TDD comes from the word test:
The idea of test to be after the fact is simple enough for even young children to grasp. They are tested, once they have studied. They got tested for an illness, once there’s a symptom for it. They can test a dish, once it’s started cooking. Testing, always comes last, not first!
Let’s consider the term “spec” instead. The terms specification, specify, and specific all stem from the Latin word “specificus”, which pertains to defining or identifying with clarity. You make something specifically clear by specifying in a specification.
The idea of specifying is simple enough for young children to grasp, even when they don’t use the word spec. The recipe they follow to cook is a spec. Builders don’t start laying bricks randomly; they follow a spec. Before you are about to drive that nail to the wall, you mark the spot first (spec). Spec mostly comes first, not last.
In the TDD process, one might view the first step more as defining a specification than merely setting up a test. Some of you might be creating spec files without realising why it’s called this way, i.e. foo.spec.js or foo_spec.rb. The next time you write that spec file, think about it for a moment: why is it called a spec?
When you think in spec-first, a specification is the defined behaviour of the elements you’re about to create.
As I have described so far in this series, the benefits of TDD hinge on the concept of laying out specifications. I believe you’ll gain the benefit even when you don’t write the spec in code. Write spec in human language if you feel that it’s easier. TDD helps you save one step by encouraging you to write the specification in code.
Unfortunately, although the word spec should intuitively come first before coding, we still don’t intuitively spec first. Knowing is not enough, we tend to miss this step.
Coding mindlessly
Seth Godin frequently emphasises the significance of specifications in his writings. In his blog post, Creating a useful spec, he wrote:
If you want someone to help, you’ll do better with a spec. It lists just four things:
What is the problem to be solved?
How are we going to solve it?
How can we test that the thing we built matches what we set out to build?
How will we know if it’s working?
[…]
If you’re not spending at least 5% of your project budget on the spec, you might be doing it wrong.
This blog is not about software, but pay attention to what Seth has written for points 3 and 4 and notice how similar it is to what we need as software engineers.
Next, pay attention to the last sentence I’ve emphasised in the excerpt. Seth implicitly suggests that many of us don’t spend enough time defining a spec, and I agree. From the misunderstood waterfall model to the misunderstood Agile, we have gone from 100% to 0% in defining specifications. The waterfall model describes distinct activities before code: requirement (spec), analysis, and design. Many of us don’t do these activities anymore after the transition to Agile.
Vaughn Vernon, the author of DDD Distilled, observed a similar experience called “the taskboard shuffle”. The taskboard shuffle happens when the entirety of the team’s design process is to move a sticky note from the “To Do” column to the “In Progress” column, which is equal to nonexistent.
While product manager may contribute to specifications, often their focus is at a broader system level. When you break the system down into smaller elements, who is going to spec the component level if not us software engineers?
Why don’t we spec?
I delved deeper into the idea of spec-first thinking as a means to make TDD more intuitive. Therefore, it’s essential to understand and address the reservations many engineers might have around thinking or writing about spec. Why might some shy away from the spec-first approach, even when its benefits are clear? Five reasons:
Spec is perceived as optional.
Some of us have survived so far in our career without thinking in spec. In my experience, we survive because someone else pays for the cost down the line. There is a misalignment of incentives.
Spec is perceived as a new skill.
Like any new skill or methodology, spec-first thinking may come with a learning curve. Those already adept at their current method might hesitate to feel like novices again.
Spec is perceived harder than code.
Even after you have acquired the necessary skills for it, you might still have the bias to do what’s easier i.e. code. This is related to the idea of task aversion, which I wrote previously here: Task Aversion and Confirmation Bias.
Spec is perceived as bureaucratic.
Some may view thinking in spec as an additional layer of bureaucracy to the development process, slowing down the joy of coding. This could be related to the misunderstanding of being Agile.
Spec is perceived as unknown or uncertain.
There are works where we can’t really define the spec upfront unless we muddle through the code. The resulting code becomes the spec (spec comes last).
In recognising these reasons, hopefully, we can address the underlying factors that might deter us from incorporating spec-first thinking and, finally, TDD in our workflow.
I believe the fifth reason causes a significant misunderstanding of TDD as some treat TDD as a one-size-fits-all approach. In such a scenario, does thinking in spec-first make sense? What do you think?
Conclusion
I’ve described why thinking spec-first could be more intuitive than test-first. Even though it’s more intuitive to think about it this way, we shouldn’t forget that we still have to do it. Knowing is not enough.
In my following essay on this series, I may tackle why TDD is not a one-size-fits-all approach so that we understand when it is applicable. It’s a difficult one to write. Stay tuned.
P.S. Apologies for the sound of my washing machine in the voiceover recording.
An excellent way of thinking about how to make TDD more human!