In double-loop TDD, what are the outer and inner loops, and which turns green last?
answer
- Two cycles, one nested inside the other
- One is slow and user-facing
- The fast one completes many times over
- Whatever opened the slice closes it
basics
~20 sThe outer loop is a failing acceptance scenario written in the user's language; the inner loop is the fast unit cycle beneath it. The inner loop goes green many times over; the outer scenario goes green last, when the behaviour is complete.
solid answer
~40 sYou open a slice of work by writing one acceptance scenario for the behaviour you are about to build and running it. It fails, and you leave it failing — that red is the statement of intent for the slice. Underneath it you run complete unit-level cycles: a failing unit test, the code that satisfies it, then restructuring while green. Each of those ends green and can be committed. You re-run the outer scenario as you go, and its failure message changes as the behaviour fills in. It turns green **last**, and that is the slice's definition of done. The point of nesting them is that the inner loop gives locality and design feedback while the outer loop gives direction and proves the parts compose into something a stakeholder asked for.
code
pseudocode · 13 linesouter = scenario("operator submits a job and receives a playable rendition")
run(outer) # RED - opens the slice
while failing(outer):
unit = next_missing_behaviour()
write_failing_test(unit) # inner RED
make_it_pass(unit) # inner GREEN
restructure(unit) # inner REFACTOR
commit() # units green, outer still red
run(outer) # failure message moves
run(outer) # GREEN - the last thing to turngo deeper
Be ready to name the two loops and their order out loud: the acceptance scenario opens the slice and fails, unit cycles run underneath, the scenario goes green last. That sequence is the whole answer at this level.
Explain the mechanics: what re-running the outer scenario tells you mid-slice, why its failure message changing is the progress signal, and what each loop gives you that the other cannot — locality below, direction above.
Show you have run this on real work: how you keep only one outer loop open, how the slice size is chosen so the loop closes in a day or two, and how you spot a scenario that went green too early because its assertion was weak.
Own the argument for the practice: what a team loses when it adopts only the inner loop, or only the outer, and how you would introduce the double loop into a team that already has both kinds of tests but runs them as separate rituals.
### One workflow, two cadences Double-loop development nests two feedback cycles that run at very different speeds. The **outer loop** is a single acceptance scenario expressed in the language of the person who wants the behaviour: a concrete example of the system doing something useful, end to end. The **inner loop** is the fast developer cycle beneath it — a failing unit-level test, the code that satisfies it, then restructuring while green — repeated as many times as the slice needs. The sequence is what makes it a *double* loop rather than two separate habits: 1. Write the acceptance scenario for the next thin slice of behaviour and run it. It fails. That failure is not an accident to be cleaned up later; it is the statement of intent that opens the slice, and it is the thing that will tell you when you are finished. 2. Leave it failing. Drop down a level and run complete inner cycles against the units you need. Each inner cycle ends green. 3. Periodically re-run the outer scenario. Its failure message moves: first a missing entry point, then a missing behaviour, then a wrong value, then a passing run. 4. The outer scenario turns green **last**. That is the slice's definition of done, and it is the moment to look for the next slice. ### Why the outer loop must not go green early An outer scenario that passes before the inner work is done is a warning, not a win. It usually means the scenario asserts something the system already did — a screen appeared, a call returned without error — rather than the outcome the user cares about. The outer loop earns its place only if its green is expensive to obtain: it should be unreachable until the behaviour genuinely exists. Equally, the outer loop must not be the *only* loop. If you drive everything from the acceptance level, each defect arrives as a single coarse failure with no locality: you know the journey is broken, not which unit is wrong. The inner loop supplies locality and design pressure; the outer loop supplies direction and the claim that the parts add up. ### A worked slice Take a video-transcoding queue. The next slice of behaviour: an operator submits a source file and receives a playable rendition. The outer scenario is one example — a submitted job, a completed rendition, an observable result the operator could point at. It goes red on the first run because nothing accepts a submission yet. Beneath it, the developer runs a series of inner cycles: a job record that validates its source reference; a queue that hands one job to one worker; a worker that reports completion; a result the operator can read. Say six inner cycles across a day and a half, each ending green and each committed. The outer scenario is re-run after most of them, failing differently every time; the changing failure is the progress bar. When the last unit lands, the outer scenario goes green, the slice is done, and the next scenario opens the next slice. ### What the two loops are for The two loops answer different questions, and confusing them is the usual interview stumble: * The **inner loop** answers *"is this unit correct, and is its design bearable?"* It runs in seconds, is called constantly, and is thrown at the problem in large numbers. * The **outer loop** answers *"does the composed system do the thing that was asked for?"* It runs in seconds-to-minutes, is called far less often, and there is exactly one of it open at a time. Only one outer loop should be open at once. Two or three half-finished acceptance scenarios in flight means two or three unfinished slices in the working tree, which is the same problem as a long-lived branch by another name. ### The cadence in practice Nothing about the double loop requires a particular level of test or a particular way of writing the scenario. It requires only that a user-visible example is written first, kept failing, and used as the completion signal. Teams that adopt only the inner loop tend to produce well-tested units that do not compose into anything a stakeholder recognises. Teams that adopt only the outer loop tend to produce slow, coarse suites with no design feedback. The double loop is the claim that these two are one workflow, not two competing disciplines — which is exactly what an interviewer is checking when they ask about it.
- How many outer loops should be open at the same time?One. Each open outer loop is an unfinished slice sitting in the working tree, so two or three at once is a long-lived branch by another name — unmerged work, unknown remaining size, nothing demonstrable. Finish the slice, let the scenario go green, then open the next one.
- What does it mean if the outer scenario passes on its very first run?It is a warning that the scenario does not assert what you think. Usually it checks something the system already did — a call returned, a page rendered — rather than the outcome the user cares about. A useful outer loop should be unreachable until the behaviour genuinely exists, so strengthen the assertion before starting the inner work.
- Why not drive everything from the acceptance level and skip the inner loop?Because a coarse failure has no locality: you learn the journey is broken, not which unit is wrong, so diagnosis time grows with the size of the system. The inner loop also applies design pressure at the level where the design actually lives. The outer loop proves composition; it is a poor debugger.
The outer scenario is the destination on the map and the inner cycles are the individual turns; you check the map repeatedly, but you only arrive once, at the end.
saying these in an interview costs you the question
- Says the acceptance scenario is written after the code
- Thinks the outer loop must stay green throughout
- Describes the two loops as separate suites, not one workflow
- Claims the inner loop is optional once scenarios exist
- Cannot say which loop turns green last
- Treats a first-run pass of the outer scenario as success