What do the design principles KISS ("Keep It Simple, Stupid") and YAGNI ("You Aren't Gonna Need It") each tell a developer to do, and how do the two differ?
answer
- KISS = form; YAGNI = scope/timing
- "Implement when needed, never when foreseen" — Jeffries, XP
- Presumptive feature = the target
- Simple ≠ short; clever one-liner isn't simple
- YAGNI never excuses tests, errors, security
basics
~20 sKISS: choose the simplest solution that works — fewer moving parts, easier to read. YAGNI: don't build a feature or extra flexibility until something actually needs it. KISS shapes how you build; YAGNI decides whether to build now.
solid answer
~50 sKISS says: among solutions that satisfy the requirement, prefer the one with the fewest concepts, indirections and moving parts, because someone else must read, debug and change it. YAGNI (from Extreme Programming) says: implement capability when a real, present need exists — never because you foresee needing it later. So KISS governs the *form* of what you decided to build; YAGNI governs the *scope and timing* of what you build at all. YAGNI targets presumptive features and speculative extensibility — the config flag with one value, the plugin system with one plugin, the abstraction layer over a database you will never swap. It does not license skipping tests, error handling, input validation, security, or sane module boundaries: those serve today's code, not a guessed future. Misapplied, KISS becomes "I didn't think about it" and YAGNI becomes "I cut corners".
go deeper
State both definitions correctly and give one concrete example of each (a config flag with one value; a clever one-liner rewritten as three clear lines). Say explicitly that YAGNI is not an excuse to skip tests or error handling.
Draw the scope-vs-form distinction crisply, list the classic speculative constructs (single-implementation interface, unused options bag, DB abstraction "in case we swap"), and mention that YAGNI's bet is that adding it later is cheap.
Frame YAGNI as an economic bet and name where the bet fails: irreversible decisions such as published APIs, wire/storage formats, and security models. Explain how KISS keeps that bet valid by keeping change cheap.
Position both as defaults inside a broader decision policy: reversible decisions default to YAGNI and get deferred to the last responsible moment; irreversible ones get explicit up-front design and a written record. Discuss how you enforce this culturally without it degrading into "no design".
## The two principles, precisely **KISS — "Keep It Simple, Stupid"** originated outside software: Kelly Johnson at Lockheed's Skunk Works (1960s) demanded aircraft repairable in the field by an average mechanic with basic tools. Transplanted to software it means: *of the designs that meet the requirement, prefer the one a competent stranger can understand and change fastest.* Simplicity is measured in **concepts a reader must hold in their head** — number of classes/functions involved, layers of indirection, branches, implicit conventions, configuration knobs, runtime moving parts (threads, caches, queues, services). KISS is **not** "fewest lines of code". A dense one-liner packing four operations, or a clever bit-twiddling trick, is *short* but not *simple*. Nor is it "no structure": splitting a 600-line function into five named steps adds lines and reduces complexity, because each piece is independently understandable. **YAGNI — "You Aren't Gonna Need It"** comes from Extreme Programming (Kent Beck, Ron Jeffries, late 1990s). Jeffries' formulation: *"Always implement things when you actually need them, never when you just foresee that you need them."* The target is the **presumptive feature** — functionality or flexibility added because someone predicts a future requirement. ## Why they are different principles - YAGNI is a **scope/timing** decision: *should this capability exist at all right now?* - KISS is a **form** decision: *given that it must exist, what shape should it take?* You can violate one while honouring the other. A speculative plugin framework can be beautifully written (KISS-clean internally) and still be a YAGNI violation, because nothing needs it. Conversely, a genuinely required feature can be implemented as an unreadable tangle — YAGNI satisfied, KISS violated. ## Typical YAGNI violations | Symptom | What it looks like | |---|---| | Config flag with one value | `strategy: "default"` and no other strategy exists | | Plugin/extension point with one implementation | Interface + factory + registry, one concrete class | | Generic "future-proof" abstraction layer | A repository wrapping the database "in case we swap it" (you won't) | | Unused parameters/hooks | `process(data, options)` where `options` is never non-empty | | Premature scaling machinery | Sharding, caching tier, message queue before any load exists | | Multi-tenancy / i18n / audit hooks | Built "because sales might sell it" | ## What YAGNI explicitly does NOT excuse This is the most common interview trap. YAGNI applies to **capability you don't need yet**, not to quality attributes serving code that exists today: - automated tests for the behaviour you just wrote - handling errors and invalid input that can occur today - security controls (authn/authz, escaping, secrets handling) for endpoints that exist - naming, cohesion, module boundaries — these make today's code cheap to change - required non-functional constraints already in the contract (e.g., a stated latency SLA) "We skipped auth because YAGNI" is not YAGNI; it is missing a present requirement. ## How they interact YAGNI is what makes KISS survivable over time. Every speculative extension point permanently raises the baseline complexity everyone must read past — so deferring it *is* how you keep the system simple. Conversely, KISS keeps YAGNI cheap: if today's code is simple and well-tested, adding the feature later when it is real costs little, which is exactly the bet YAGNI makes. ## The counterweight Both principles assume change is cheap. When it is not — a published API other teams depend on, an on-disk/wire data format, a security model, a persistence schema in a system with no migration story — you must design deliberately up front, because retrofitting is expensive or impossible. YAGNI defers **reversible** decisions; it does not tell you to be careless with irreversible ones.
- Someone justifies skipping input validation and tests by saying "YAGNI". Is that a correct use of the principle?No. YAGNI concerns capability nobody needs yet. Validation and tests serve code that exists today and make it cheap to change — they are present requirements, not speculation. Misusing YAGNI this way is how it gets a bad reputation.
- Is a hand-rolled 300-line function 'simple' by KISS because it has no abstractions?No. KISS minimises the concepts a reader must hold at once, not the number of named units. Splitting that function into a few well-named steps usually adds lines while reducing what the reader must understand at any moment.
KISS is packing a suitcase neatly so anything is easy to find. YAGNI is not packing the snorkel for a ski trip because "we might detour to the coast". Different decisions: how you pack versus what goes in.