In test-driven development, what goes wrong when a team always skips the refactor step?
answer
- Three steps, three different payoffs
- Green is not the end of the cycle
- The lost one is design feedback
- Duplication and setup accrete quietly
- Restructure while green, commit separately
basics
~20 sYou keep the regression protection but lose the design payoff. The code becomes whatever the quickest path to green left behind: duplicated blocks, growing setup and a branch per case, until changing it costs more than the tests save.
solid answer
~50 sThe three steps buy different things. The failing test buys a specification, making it pass buys working behaviour, and restructuring while green is the only step that buys design. Skip it and the practice degrades into test-first coding: still useful as a safety net, but the structure of the system is now an accident of the shortest path to green. The debt shows up in a predictable order — near-duplicate blocks, setup that grows with every case, a conditional per case, widening parameter lists — and it compounds, because each skipped step makes the next restructuring larger and scarier. The test code rots the same way, which is how a suite becomes "too expensive to maintain". The fix is cadence, not a backlog item: restructure only while green, keep it inside the cycle that revealed the need, and commit it separately from behaviour changes.
code
pseudocode · 7 linesfunction envelopeFee(envelope):
if envelope.signers == 1 and envelope.region == "A": return round(base * 1.00)
if envelope.signers == 1 and envelope.region == "B": return round(base * 1.05)
if envelope.signers == 2 and envelope.region == "A": return round(base * 1.00) + round(perSigner)
if envelope.signers == 2 and envelope.region == "B": return round(base * 1.05 + perSigner)
# ... thirteen more branches, each added by a passing test
return round(base)go deeper
Remember that the cycle has three steps and that green is not the finish line. Be ready to name what the third step gives you and one symptom of skipping it, such as duplicated blocks across cases.
Explain the mechanics: restructure only while the suite is green, commit behaviour and structure separately, and treat the third similar block as the trigger. Describe the accretion order — duplication, setup growth, a branch per case.
Show how you recover a codebase where the step has been skipped for months: small green-to-green batches inside normal work, restructuring the tests too, and resisting a big-bang cleanup ticket.
Own the incentive problem. The step has no visible deliverable, so it loses to features by default; be ready to say how you make it part of the definition of a change rather than a line item someone can trade away.
### The step that carries the design payoff The cycle has three steps, and they buy different things. The failing test buys you a specification and proof that the assertion is wired to something. Making it pass buys you working behaviour. The third step — restructuring while everything is green — is the only one that buys you **design**. Drop it and you still have a regression suite and you still have working code, but you have converted the practice into "test-first coding": the tests come first, and the structure of the system is whatever the quickest path to green happened to leave behind. That is why the answer to "we do the first two steps, we just skip the third when we are busy" is not "you are doing most of it". You are doing the half that does not compound. ### Why it gets skipped Green feels like done. The step has no visible deliverable — nobody demonstrates a restructuring at a review — and it is the easiest thing to trade away under a deadline because nothing breaks today. It is also skipped out of fear: a team that has never restructured under a suite it trusts believes restructuring is risky, and every skipped step makes the next one riskier, which confirms the fear. Finally it is skipped by accounting: teams that insist a restructuring needs its own ticket have guaranteed it will be scheduled behind features forever. ### What accretes The debt shows up in a recognisable order. First near-duplicate blocks: the third case looks like the second with one value changed. Then setup growth — every new case adds two more lines of arrangement, and the arrangement is copied rather than shared. Then conditionals: a branch per case rather than a structure that makes the cases uniform. Then the parameter lists widen, because each new branch needs one more input threaded through. A four-person team on a document e-signing flow shipped six weeks of small green steps without a single restructuring. The per-envelope fee calculation went from three branches to seventeen, each added by a test that passed. A currency-rounding drift lived in the fourteenth branch for weeks: every branch was individually covered, but nobody could see that two branches disagreed about where the rounding happened, because there was no single place where rounding happened. ### The test code rots too The refactor step covers both sides. Test duplication is the more dangerous kind, because a copied setup block is copied again the moment it is easier to copy than to understand. Suites that were never restructured are exactly the suites teams later describe as "too expensive to maintain" — which then becomes the argument for writing fewer tests, closing the loop. ### Recovering the habit - **Refactor only while green, and commit at green.** The step is safe precisely because the suite passes before and after. Restructuring while a test is red mixes two kinds of change and you lose the ability to say which one broke things. - **Keep it inside the cycle, not on a backlog.** The restructuring belongs to the change that revealed the need for it — that is when you understand the code and when the cost is smallest. - **Make it a separate commit from the behaviour change.** A reviewer can then read one commit that adds behaviour and one that changes no behaviour, and check the second by reading rather than reasoning. - **Take the small ones every cycle.** The step is thirty seconds of work most of the time — extract the duplicated block, rename the thing you just misread, collapse two branches. Batching it into a quarterly effort is how it stops happening. - **Let the duplication trigger you.** Two similar blocks are information; the third is an instruction. This is the cheapest rule to teach a team that has been skipping the step. ### What to say in an interview Interviewers ask this because it separates people who have read about the cycle from people who have run it. The strong answer names the specific loss — design feedback, not regression protection — and then describes the observable symptoms in a codebase where the step has been skipped for a while, rather than repeating that refactoring is important. Be honest that the empirical evidence on how much the practice improves design is mixed and contested in the literature; the argument for the third step is a mechanism you can demonstrate, not a number you can cite.
- Should the refactor step ever touch the tests themselves?Yes, and it is the half teams forget. Copied setup blocks and near-duplicate cases spread faster in test code than in production code, because copying is always the cheaper local move. A suite nobody restructures is the suite that later gets described as too expensive to maintain, which becomes the argument for writing fewer tests. Restructure both sides in the same green window.
- Your team says there is no time to restructure this iteration. What do you propose?Argue the step back into the cycle rather than onto a backlog. Most restructurings that belong to the third step are seconds of work — extract the block you just duplicated, rename what you misread, collapse two branches — and they are cheapest at the moment the change reveals the need, while you still understand the code. A separate ticket guarantees it is scheduled behind features indefinitely and grows until it needs its own project.
saying these in an interview costs you the question
- Treats a green test as the end of the cycle
- Says restructuring needs its own ticket and a later iteration
- Restructures while a test is still red
- Only ever restructures production code, never the tests
- Claims writing tests first produces good design by itself