An honest scorecard
TDD is a tool, not a religion. Where it shines:
- clear specs: you know the expected outputs, like fizzbuzz or a tax rule, so tests write themselves
- bug fixes: reproduce the bug as a failing test first, then fix. The red-to-green flip proves the fix, and the test guards against the bug returning forever
- tricky pure logic: parsers, date math, pricing, anywhere edge cases breed
Where it fights you:
- exploration: you do not know what you are building yet, so specs do not exist to test against
- visual work: whether a layout looks right is not an assert
- thin glue code: a one-line wrapper rarely earns a test
The pros' habit even outside strict TDD: never fix a bug without first writing the test that catches it. That single rule carries most of TDD's value.
The first move on a bug report
A user reports that invoices for exactly 100 items get the wrong discount. Following the bug-fix rule, the very first action is to write a test asserting the correct discount for 100 items and watch it fail.
The failing test reproduces the bug on your desk, which is the necessary precondition for fixing anything. Note that 100 items is a boundary, so lesson 3-2 already predicted this is where a bug would live.
Writing the test first buys three things that fixing first does not:
- Proof. When your change turns the test green, you know you fixed the reported problem and not a different one that looked similar.
- A permanent guard. The test stays in the suite, so this exact regression can never sneak back in unnoticed.
- A forced diagnosis. Reproducing it precisely often reveals the real trigger, which may turn out to be 100 exactly rather than any large order.
The tempting alternative is to read the code, spot something suspicious, change it, and eyeball an invoice. That can even work, and it leaves you with no evidence and no protection, which is why the rule is worth following even when the fix looks obvious.
The third beat
The mantra is red, green, refactor, and the third word is refactor.
That beat exists because minimal green code is often ugly. Hard-coded returns, duplicated branches, and awkward names are all expected outputs of writing the smallest thing that passes, and leaving them there would make the codebase steadily worse.
The passing tests from beats one and two are what make cleaning up risk-free. Refactoring means changing how the code is written without changing what it does, which is exactly the definition from lesson 1-2, and you practiced it there on count_vowels.
The order of the beats is what makes the third one safe. Refactoring code that has no tests is the leap of faith lesson 1-2 described, while refactoring immediately after going green means the net is at its tightest, since you have just watched every relevant test pass.
Skipping the refactor beat is the most common way teams abandon TDD without noticing. The tests keep passing, the code gets steadily harder to change, and eventually the suite is blamed for slowing things down when the real cause was two hundred skipped cleanups.
The weakest fit for test-first work
Strict test-first TDD fits worst on a quick throwaway prototype built to explore whether an idea is even possible.
Exploration has no spec yet, so there is nothing definite to assert. Writing tests against a design you are about to throw away costs time and, worse, anchors you to the first shape you imagined, which is the opposite of what exploration is for.
The productive approach is to prototype freely, learn what the problem actually is, and bring TDD in once real requirements crystallize. Any code from the prototype that survives into the real thing gets tests then, written against the spec you now understand.
| Kind of work | Fit for TDD | Why |
|---|---|---|
| billing or pricing rule | strong | exact expected outputs exist |
| parser or date math | strong | edge cases breed here |
| reproducing a bug | strong | the failing test is the report |
| throwaway prototype | weak | no spec to assert against |
| visual layout | weak | correctness is a judgment, not an assert |
| one-line glue wrapper | weak | the test would restate the line |
The three strong rows share one property, which is that somebody can say in advance what the right answer is. That is the real test of whether TDD applies, and it is a more useful question than asking whether the code is important.