Core principle
YAGNI — You Aren't Gonna Need It
Build what the current requirement needs — nothing more. Imagined future needs cost you now and rarely pay off later.
✗ The problem
Speculative generality: designing for futures that never arrive
The task is "save a note". The code ships a plugin system, five export formats,
a 12-flag config object, and an abstract strategy — for one localStorage call.
class StorageStrategy { save(k, v) { throw 'abstract'; } }
class LocalStorageStrategy extends StorageStrategy { /* only impl */ }
function saveNote(text, {
strategy = new LocalStorageStrategy(),
exportFormat = 'json', // txt/md/pdf/xml unused
plugins = [], // none exist yet
// ...9 more flags nobody sets
} = {}) {
strategy.save('note', text);
}
You pay to build, test, and maintain code for futures that never arrive —
every unused branch is a bug waiting to happen.
✓ Build only what's needed now
Ship the one line the requirement actually asks for
No strategy, no config, no plugins — just the behavior today's requirement needs.
Before — bloated, hypothetical
function saveNote(text, {
strategy = new LocalStorageStrategy(),
exportFormat = 'json',
plugins = [],
/* 9 more flags */
} = {}) { strategy.save('note', text); }
After — exactly what's needed
function saveNote(text) {
localStorage.setItem('note', text);
}
Need a second storage backend for real one day? Add the abstraction
then — see Open/Closed.
✓ See it live
Toggle speculative features — watch cost climb, value stay flat
These are "needed now". Toggle the "maybe someday" ones ON and watch complexity, maintenance cost, and surfaced bugs rise — while shipped value never moves.
✅ Save note to storageneeded now
✅ Show saved confirmationneeded now
🔌 Plugin systemmaybe someday
📤 5 export formatsmaybe someday
⚙️ 12-flag config objectmaybe someday
🧩 Abstract StorageStrategymaybe someday
Complexity / LOC18 lines
Maintenance cost0%
Bugs surfaced0
Shipped value delivered to the user: 2 / 2 core features — constant, no matter how many speculative toggles are ON.
✓ Takeaway
Build for the requirement you have, not the one you imagine
- Don't build for imagined futures — implement the current requirement, refactor when the need becomes real.
- Speculative code is cost + risk (build, test, maintain, debug) with no payoff until — if ever — it's used.
- Pairs with Open/Closed: add the abstraction when the second real case shows up, not before.
- Caution: YAGNI isn't an excuse to skip real design or ignore known, certain near-term requirements.
Back to all topics →