Martin Fowler frames YAGNI ("You Aren't Gonna Need It") as an economic trade-off between building a presumptive feature now and carrying it. Walk through those costs, and name the situations where applying YAGNI is the wrong call.
answer
- Four costs: build, delay, carry, repair
- Carry cost is paid daily, by everyone
- Wrong shape is worse than wrong feature
- One-way vs two-way doors; last responsible moment
- YAGNI presumes clean code + tests + refactoring
basics
~20 sBuilding early costs the build itself plus a delay to real work, and if you guessed wrong you carry and repair dead complexity forever. YAGNI fails where changing later is expensive or impossible: published APIs, stored/wire data formats, security models, and hard non-functional requirements.
solid answer
~60 sFowler's model names four costs. **Cost of build** — the effort to write the presumptive feature. **Cost of delay** — what real, needed work is pushed back while you build it. **Cost of carry** — the permanent tax the extra code imposes on everyone reading, testing and changing the system, paid every day it exists. **Cost of repair** — when the guessed feature turns out to be subtly wrong (the common case), you pay to understand and rework it, often more than building it fresh would have cost. YAGNI wins whenever the later cost of adding the feature is roughly the same as building it now, which holds for most internal, reversible design. It fails when adding it later is disproportionately expensive: published APIs and wire contracts with external consumers, persisted data formats and schemas without a migration story, security and multi-tenancy/isolation boundaries, and non-functional constraints (latency, availability, audit, regulatory) that are structural rather than additive. Distinguish two-way doors, where you default to YAGNI, from one-way doors, where you design deliberately up front.
go deeper
Name the idea that building early is not free and give the plain-language costs: time spent, work delayed, extra code to maintain. Note that a guessed feature often turns out to be the wrong shape.
Reproduce all four costs by name and explain that carry cost is recurring. Give one concrete example where you deferred and it was cheap, and one where deferring would have been costly.
Make the economics explicit, tie the decision to reversibility (one-way vs two-way doors, last responsible moment), and enumerate the exception classes: external contracts, persisted formats, security boundaries, structural NFRs, cross-team migrations.
Turn it into policy: which decision classes require an ADR and up-front design, how you buy optionality cheaply (versioned envelopes, expand/contract migrations, private-preview APIs), and how you reduce the cost of change itself so the YAGNI default holds for more of the system.
## The four costs (Fowler's YAGNI bliki entry) Martin Fowler's argument is explicitly economic, not aesthetic. Building a **presumptive feature** — capability added because someone predicts a future need — incurs: 1. **Cost of build** — hours spent designing, coding, testing and documenting it now. 2. **Cost of delay** — the value lost because features that are needed *today* shipped later. In a competitive or feedback-driven product, delay may dominate everything else. 3. **Cost of carry** — the ongoing drag the extra code imposes: more to read, more surface to test, more to keep compiling, more to migrate at every framework upgrade, more to hold in your head while making unrelated changes. Crucially this is paid **every day**, by everyone, whether or not the feature is ever used. 4. **Cost of repair** — if the guess was *nearly* right (the usual outcome, worse than being flatly wrong), you must now understand the half-fitting design and bend it to the real requirement. That commonly costs more than deleting it and starting over, and people rarely delete, so the half-fitting design persists and keeps charging carry cost. The wrong guess has two flavours: - **Wrong feature**: the capability is never needed → pure build + carry loss. - **Wrong shape**: the capability is needed, but not in the form you built → build + carry + repair. ## The bet YAGNI is making YAGNI is rational when **cost(build later) ≈ cost(build now) + interest**, i.e. when deferring doesn't make the work materially harder. Two things make that true: - the code you have is clean, tested and easy to change (which is why YAGNI depends on continuous refactoring and good test coverage — Fowler is explicit that YAGNI without those is just recklessness); - the change is **local**, contained behind boundaries you control. When those don't hold, the bet is bad. ## Where YAGNI is the wrong call Categorise by *reversibility* and *blast radius*: | Situation | Why deferring is expensive | |---|---| | Published API / client SDK / event schema with external consumers | You cannot unilaterally change it later; you need versioning, deprecation windows, coordinated migrations. Extensibility (versioning field, additive-only evolution rules) must exist from v1. | | Persisted data and wire formats | Retrofitting a field or a shape onto terabytes of existing records requires backfills and dual-write/dual-read periods. Information you never captured is simply gone. | | Security and isolation model | Adding authorization, tenant isolation or encryption boundaries after the fact means auditing every path; getting it wrong once may be a breach, not a bug. | | Structural non-functional requirements | Latency, throughput, availability, geographic residency, auditability often constrain the architecture (partitioning, replication, event capture) rather than adding to it — retrofitting means a rewrite. | | Regulatory / compliance requirements already known | Audit trails, retention, consent records: if the data wasn't recorded, it cannot be reconstructed later. | | Anything requiring coordinated migration across many teams/services | The cost of change scales with the number of coordinating parties, not with the code size. | Note the pattern: these are cases where **cost(later) ≫ cost(now)** because of coordination, data loss, or irreversibility — not because someone "feels" the feature is likely. ## The decision framework to state in an interview 1. **Is the need real or presumptive?** Real, present need → build it; YAGNI does not apply. 2. **If presumptive: is the decision a two-way door (cheap to reverse) or a one-way door?** Amazon's framing; Lean's equivalent is the **last responsible moment** — defer until further delay would eliminate an important option. 3. **Two-way door → defer.** Keep the code clean so the later build is cheap. Optionally record the anticipated direction as a note/ADR without building it. 4. **One-way door → pay for design now**, but pay the *minimum* that preserves optionality: an explicit version field, an extensible envelope, an additive-only schema policy, a seam at the true external boundary. Preserving the *option* is cheaper than building the *feature*. 5. **Reduce irreversibility itself.** Often the best move isn't "build it now" but "make later change cheap": add a migration framework, add expand/contract deployment discipline, keep the API internal until requirements settle, ship behind a private preview. ## Common misuses to call out - **YAGNI as an excuse for no design.** It only forbids *presumptive features*; it says nothing against good factoring, tests, or thinking. - **Anti-YAGNI by anecdote.** "We once needed it" — survivorship bias; you remember the guess that paid off, not the ten that rotted. - **Confusing extensibility with capability.** Making a message envelope forward-compatible is cheap optionality; building the unused feature behind it is a presumptive feature. - **Ignoring the carry cost of the platform you chose.** A speculative microservice split or a home-grown framework is a YAGNI violation at architecture scale, with a carry cost measured in team-years. ## Sharpening it with numbers If you can, quantify: probability p that the feature is needed, cost B now, cost L later, daily carry c over d days, repair cost R with probability of wrong shape q. Building now is justified roughly when `B + c·d + q·R < p·L`. You will rarely have real numbers, but framing the argument this way stops the debate being about taste and shows a senior grasp of the trade-off.
- A PM insists a competitor's feature is coming and wants the hooks built now. How do you respond?Separate the option from the feature. Agree cheap, reversible measures that preserve the option — an additive-friendly schema, capturing the data now because data cannot be reconstructed later, keeping the API private until it settles — and decline to build the unused capability, showing the carry and repair costs plus the delay to committed work.
- Why is a wrong-shape guess often worse than a wrong-feature guess?An unneeded feature can, in principle, be deleted. A near-fitting one gets kept and bent: you pay to understand it, adapt it, and preserve its existing behaviour, and its shape constrains the correct design. Repair frequently exceeds greenfield build, and teams rarely take the delete option.
- Does YAGNI apply to non-functional requirements like scaling?It applies to speculative scaling machinery — sharding, caches and queues for load that doesn't exist. It does not apply to a scale requirement already in the contract, because throughput and availability targets usually constrain the architecture rather than bolt onto it; those must be designed for from the start.
Fitting your house with a lift shaft in case you're ever immobile: cheap-ish to build, but it eats floor space every day (carry), delays the kitchen you actually need (delay), and when the real need comes the shaft is in the wrong corner (repair). Leaving a wall non-load-bearing so a lift can be added later is the good move: you buy the option, not the lift.