skip to content

When starting a feature with TDD, how do you choose outside-in or inside-out?

level: seniorimportance: should knowfreq 45%

answer

  1. Choose by where the risk sits
  2. Unknown collaboration versus unknown rule
  3. Is the outer contract already agreed?
  4. Parallel work needs published seams
  5. Mix the two, then re-point the stand-ins

basics

~20 s

Start where the uncertainty is. If the collaboration and the boundary are unclear, drive outside-in and invent roles at the moment of need; if the boundary is agreed and a domain rule is the hard part, drive inside-out.

solid answer

~40 s

Choose by the shape of the risk, per feature and sometimes per layer. Drive **outside-in** when the open question is collaboration — who talks to whom, what the entry point needs, how responsibilities split — or when several people must work in parallel and publishing the seams early lets them. Drive **inside-out** when the outer contract is already fixed and the difficulty is a rule or algorithm, so the first cycle lands on the hard part instead of the fourth. Weigh the failure modes too: outside-in risks a green suite over a mismatched seam, inside-out risks discovering an awkward boundary after the core has set. Most strong answers mix — sketch outside-in to find the seams, switch to inside-out for the gnarly collaborator, then deliberately re-point some outer tests at the now-real objects.

go deeper

for a junior

Recall that the choice exists at all, and one deciding factor you can defend — such as starting outside-in when you do not yet know what the collaborators should be. Do not claim a universal winner.

for a middle

Give two or three concrete deciding factors and what each implies: an already-agreed outer contract, an unclear split of responsibilities, or an algorithm that carries the real difficulty. Say that the choice is per feature and reversible.

for a senior

Demonstrate that you have made this call under pressure: weigh the failure modes against each other, describe how you mix the two inside one feature, and say when you go back to replace stand-ins with the real collaborators.

for a principal

Own the organisational angle — how the choice interacts with several pairs working one feature, with legacy code that resists isolation, and with what you require before a release. Standardise the seam-verification rule rather than the starting point.

### The question behind the question An interviewer asking this is not checking whether you know two labels. They are checking whether you pick a starting point from the shape of the risk in front of you, or from habit. Test-driven development leaves the starting point open. **Outside-in** begins at an outer boundary, inventing collaborator roles as the need appears and standing them in until they are built. **Inside-out** begins with domain behaviour, built from real objects, and connects the outside world last. The choice is per feature — sometimes per layer inside one feature — and it is reversible. ### What actually decides it **Where is the uncertainty?** If you do not yet know what the collaborators should be, how responsibilities should split, or what the entry point needs, outside-in turns that uncertainty into a sequence of concrete design decisions taken at the moment of need. If the collaboration is obvious and the risk is a gnarly rule — a rating calculation, a deduplication window, a parsing edge case — inside-out gets you to the hard part on the first cycle instead of the fourth. **Is the outer contract already fixed?** An agreed message schema or a published endpoint shape removes the main thing outside-in is good at discovering. There is less to invent at the boundary, so start where the open questions are. **How stable is the collaborator boundary?** Outside-in leaves stand-ins in place, and a stand-in is a frozen picture of a contract. Against a volatile or externally-owned collaborator those pictures rot quietly. Against a stable, well-understood seam they cost little. **Which failure can you afford?** Outside-in's characteristic failure is a green suite over a mismatch — two sides of a seam that never met. Inside-out's is discovering late that the boundary is awkward, after the core has committed to a shape. Ask which of those is cheaper to absorb in this codebase. **How many people are on it?** With an eleven-person team and three pairs on one feature, outside-in has a coordination advantage that has nothing to do with design purity: inventing the roles first publishes the seams, so pairs can take one each and integrate against agreed signatures instead of waiting. Solo on a small feature, that advantage disappears. **Do you already have an outer harness?** If an end-to-end or acceptance-level test can be written cheaply, outside-in has a natural outermost loop to hang the work from. If standing up the boundary takes a day, that is a day before the first red test. ### The answer that lands The strong answer refuses the dichotomy and then says how it mixes them. A common shape: sketch outside-in far enough to discover the seams and to get one honest behaviour running end to end, then switch to inside-out for whichever collaborator carries the real domain difficulty, building it with real objects and its own tests. Afterwards, deliberately re-point some outer tests at the now-real collaborators rather than leaving every seam permanently stood in. ### A worked decision The smart-meter ingest path: accept a reading, discard duplicates in a rolling window, convert pulse counts to kilowatt-hours, persist. The inbound schema was agreed with the device vendor months earlier — no discovery there. The conversion has awkward cases: meter rollover at `999999` pulses, a documented pulses-per-kilowatt-hour constant of `1600`, and readings that arrive out of order. So the team drove the converter and the duplicate window inside-out with real objects, then wrapped them outside-in from the handler to settle the storage and error-reporting seams, which were genuinely open. They also made one rule explicit, having been bitten before: the seam to the store gets a test that exercises the real store, because the previous release rounded every stored reading to two decimal places while the stood-in store in every handler test accepted six — a silent corruption that no green suite had any way to see. ### Judgement, not doctrine Say plainly that the evidence for either school producing better designs is contested, and that experienced teams converge on mixing rather than on a winner. A candidate who argues one school is simply correct is telling you they have only worked one way. A candidate who says "outside-in when the collaboration is the unknown, inside-out when the rule is the unknown, and re-point the stand-ins once the real thing exists" has actually made the call before.

  • You start outside-in and three cycles in the invented roles feel wrong. What do you do?
    Treat it as the feedback you asked for and change the roles rather than defending them — that is the whole point of inventing them at the moment of need. Reshape the seam, update the outer tests, and if the difficulty turns out to sit inside one collaborator, switch and build that piece inside-out with real objects before returning to the boundary.
  • How does an existing legacy codebase change the choice?
    It usually pushes towards outside-in for a different reason: you often cannot construct the core objects in isolation, so the reachable seam is at a boundary you can wrap. You stand in what you cannot instantiate, get a behaviour pinned, and only then work inward. The stand-ins there are a consequence of the legacy shape, not a design preference.
  • Does the choice matter for how you demonstrate a feature is finished?
    Yes. An outside-in start already gives you a test at the outer boundary that describes the feature in the user's terms, so completion evidence exists from the first cycle. Inside-out reaches that point last, so plan explicitly for the boundary-level test rather than assuming a stack of green core tests demonstrates the feature works.

saying these in an interview costs you the question

  • Argues one school is always correct regardless of context
  • Picks a style by habit and cannot state a deciding factor
  • Never considers whether the outer contract is already fixed
  • Ignores that stand-ins left at a seam can hide a mismatch
  • Treats the choice as irreversible once the first test is written

context