Skip to main content
AI & Technology

YAGNI — The Discipline That Saves Software Projects From Death by Over-Engineering, With Martin Fowler's 4 Hidden Costs

YAGNI (You Aren't Gonna Need It) is a discipline from Extreme Programming: 'don't write what you don't need yet.' Simple to say, hard to live by — teams worldwide still fail at this every day. This article covers the 4 costs Martin Fowler warns about (Build, Delay, Carry, Repair), 5 signals you're over-engineering, when YAGNI becomes a trap, and how the Enersys team applies it on real client work.

21 May 202614 min
YAGNISoftware EngineeringExtreme ProgrammingOver-EngineeringTechnical DebtMartin FowlerSoftware DesignSoftware House

TL;DR

YAGNI = "You Aren't Gonna Need It" — a rule from Extreme Programming, coined by Kent Beck and most famously summarized by Ron Jeffries:

"Always implement things when you actually need them, never when you just foresee that you will need them."

Sounds like textbook advice. Yet software teams worldwide still violate it every day.

Why? Because YAGNI runs against the engineer's instinct. Good engineers are trained to plan ahead, to design "flexible" abstractions, to add "just in case" options. That instinct is the trap.

This article covers:

  • Where YAGNI came from and why the XP community treats it as essential
  • Martin Fowler's 4 cost categories — Build, Delay, Carry, Repair
  • 5 signals you're violating YAGNI on your current project
  • When YAGNI is wrong — situations that genuinely require investing early (security, audit, compliance)
  • How the Enersys team applies YAGNI on real Odoo / AI / PDPA work

If you're a CTO, tech lead, product manager, or business owner hiring a software team, this is worth your 14 minutes.


What Is YAGNI — And Where Did It Come From

YAGNI isn't new and isn't a 2026 trend.

It dates back to the late 1990s — when Kent Beck wrote Extreme Programming Explained (1999) and the XP team experimented with the Chrysler Comprehensive Compensation system. The methodology centered on TDD, refactoring, pair programming, and simple design.

XP includes the principle "Do The Simplest Thing That Could Possibly Work" (DTSTTCPW). YAGNI is the enforcement mechanism — because "simplest" gets rationalized into "complex" very quickly without a guardrail.

Ron Jeffries (one of three co-founders of XP alongside Beck and Cunningham) put it plainly:

"Always implement things when you actually need them, never when you just foresee that you will need them."

This is still the cleanest definition of YAGNI — short, sharp, actionable.

Since then YAGNI has entered engineering vocabulary worldwide — cited in code reviews, in architecture meetings, in PR descriptions. And yet teams still violate it daily, because it goes against the urge to "be prepared."


The 4 Costs of "Just In Case" — Martin Fowler's Framework

In 2015, Martin Fowler wrote his bliki entry on YAGNI, laying out the cost framework that is still the reference in the industry today.

Speculative code sounds like a small problem ("a few extra lines"). Fowler shows the cost actually splits into four distinct categories.

1. Cost of Build

The labor and time spent analyzing, coding, testing, and documenting a feature that ultimately doesn't get used.

The math is simple. If you spend 2 weeks on a "just in case" feature and 6 months later nobody uses it, those 2 weeks are a 100% loss.

Numbers our team sees consistently (in our own work and in audits of other teams' codebases):

  • 30–50% of "just in case" features → never used
  • ~20% used but in a different shape than designed → cheaper to rewrite
  • The remaining 30–50% actually used → still needs adjustment because requirements shifted

Out of 100% invested, you may get back only 20–30% of what you planned for.

2. Cost of Delay

This is the invisible cost — and the one that hurts most.

Two weeks spent on speculative feature A is two weeks you could have spent on feature B that your customers want now.

Fowler's example: an insurance startup spending six months building a piracy-insurance pricing engine (not yet selling) instead of storm-risk pricing (selling today). The team missed the storm-risk market window entirely.

In real business terms:

  • Time lost = revenue not earned
  • A competitor that doesn't over-engineer ships faster → wins customers first
  • A 1-month market-timing delay can mean losing a 1–2 year market position

From the client side of a software house engagement (e.g., Enersys clients), this is the opportunity cost of the system not being in production yet.

3. Cost of Carry

This one accrues silently — and most teams don't track it.

Every line of "just in case" code is overhead that everyone pays:

  • Read it (onboarding)
  • Understand it (debugging)
  • Maintain it (when dependencies shift)
  • Test it (regression coverage)
  • Be careful around it (touching related features)

A pattern we saw recently while auditing an Odoo codebase for a new client:

The original team built a multi-tenant abstraction layer at the start of the project. Three years later the system is still single-tenant and there's no plan to change.

That abstraction became:

  • Three layers deep — tracing a bug means opening 5–6 files
  • 2–3 week onboarding tax for every new developer
  • Every new feature has to be checked against "does this abstraction handle it?"
  • Odoo version upgrades break at the abstraction layer, making migrations painful

That's a cost of carry that compounds every month.

4. Cost of Repair

When "the day you need it" finally arrives — six months, a year, or three years after writing — the "just in case" code doesn't match the actual requirement almost every time.

Why:

  • When written: guessed from a requirement that was in your head and never verified
  • When actually used: real requirement differs because the business changed, user feedback came in, regulation shifted

So you have to:

  • Delete the old code
  • Rewrite from scratch
  • Or "adapt" the old — which is often harder than rewriting

Fowler is blunt: a feature left untouched for 6 months is more often outdated than useful.

This is technical debt without the borrowing benefit — you didn't borrow anything to do something useful; you're just paying maintenance.


Why Good Engineers Still Fail at YAGNI

Strong engineers fall into over-engineering daily. Why?

Reason 1 — The Instinct to "Be Prepared"

Engineers are trained to think ahead — design patterns, scalability, extensibility, every textbook lesson.

It feels wrong to deliberately think: "today I will write only what's needed." It feels amateur.

Reason 2 — Identity of the "Good Engineer"

Many engineers tie their self-worth to producing abstractions that look professional.

Abstractions look impressive — they suggest you know your patterns, SOLID, Clean Code.

But the truly great engineer knows — the best abstraction is the one that was actually necessary.

Reason 3 — Resume-Driven Development

Some teams build unnecessary abstractions because they want "designed microservices at X scale" on a resume — when the actual system has 50 users.

That's not just an individual failing — it's an industry that rewards complexity over simplicity.

Reason 4 — "It'll Be Harder to Add Later"

A plausible-sounding argument: "It's easier to add this now than later."

But the argument fails on several fronts:

  • 70%+ of features "we'll need later" are never actually needed
  • When you do need it, the real requirement usually differs from what you guessed
  • A smaller, cleaner codebase is easier to extend than a larger one full of speculative scaffolding

Reason 5 — Management Pressure

Sometimes leadership asks "can this scale to a million users?" before there's a single user.

The team over-engineers to answer that question — instead of saying: "we don't need that today; let's revisit when we approach 100K."


5 Signals You're Violating YAGNI

Quick self-audit. Watch for these in your current project:

1. A "Manager" or "Factory" Class That Handles One Type

A UserFactory that produces exactly one kind of User isn't a factory — it's over-abstraction.

A UserFactory earns its keep when you need to build multiple user shapes (regular, admin, guest) from multiple sources. If you're not there yet, drop it.

2. Configuration Options Nobody Ever Changes

Every config option = an extra code path = an extra test case = more cognitive load.

If a config has had the same value for six months, hardcode it. Bring the option back the day you actually need it.

3. Interfaces With a Single Implementation

A PaymentProvider interface whose only implementation is StripePaymentProvider — the interface just adds navigation friction without providing real benefit.

Use the concrete class. Extract an interface the day a second implementation is real.

4. Database Fields/Columns With No Code Reading Them

A users.metadata JSON column kept "just in case" — but no code path reads or writes it.

Every field is a responsibility — harder schema migrations, larger backups, and PDPA auditors asking what you're storing.

5. "Generic" Functions Used Once

utils/processAnyEntity() that can handle anything — but the codebase only calls it from one place.

Single-use functions belong inline at the call site. The reader doesn't need to hop files.


When YAGNI Becomes a Trap

YAGNI is a guideline, not dogma.

There are situations where you must invest early — because adding later would be too expensive or too risky.

Security and Compliance

Not a YAGNI case. If your system handles PII under PDPA / GDPR or financial data, build security in from day one:

  • Input validation
  • Authentication / authorization
  • Audit logging (every action touching PII)
  • Encryption at rest

Retrofitting security into a shipped system is expensive and risky.

Audit Trail and Logging

If the system has business workflows that need to be traced retroactively, instrument audit logs from day one.

Storage cost is tiny compared to the opportunity cost of an event happening with no log.

Data Schema Decisions

Database schemas — especially core tables — are hard to change later.

Invest in schema design upfront (not over-engineering, but a sensible shape) since the cost of changing it after data lands is high.

External API Contracts

A public API your customers consume is hard to change because it affects many downstream consumers.

Design it carefully for v1 — versioning, error format, pagination.

YAGNI doesn't apply cleanly here because cost of repair (breaking compatibility) is steep.


YAGNI vs. Refactoring — A Common Misunderstanding

Many people think YAGNI means "no refactoring." Wrong.

Fowler is explicit — YAGNI requires a maintainable codebase to work.

The pattern is:

  • Write only what's needed (YAGNI)
  • When you need more → refactor existing code, then add (Refactoring discipline)
  • Good test coverage → refactoring stays safe (TDD)
  • Continuous integration → ship small changes confidently (CI/CD)

If the team writes "minimal" code but the codebase is messy, untested, and painful to deploy, YAGNI turns into a technical-debt generator.

This is exactly why Beck designed XP as a bundle of practices, not a single rule.


How the Enersys Team Uses YAGNI in Practice

As a software house doing Odoo, AI Integration, and Data Privacy (PDPA) work for Thai enterprise clients, YAGNI is a default guideline on every engagement.

Not because it's fashionable — but because clients pay real money and we have to deliver value for every baht.

Discovery Phase — Ask "When Will It Be Used?"

Before any feature gets greenlit, we ask:

  • Who will use this feature?
  • How often?
  • Can users still do their job without it?
  • Is there a simpler alternative?

If the answer is vague → defer. Not in scope for this round.

Scope Negotiation — Separate "Must Have" From "Nice to Have"

Many clients send requirement lists with 100+ items — and a few "nice to haves" can push the timeline out 2–3 months.

The consultant's job is to ask directly: "If this isn't in by next month, does the business suffer?"

If not → push to phase 2.

Architecture Decisions — Start Simple, Refactor Later

Most Odoo projects begin with standard modules + minimal customization.

We don't build our own framework, don't introduce a custom abstraction layer, and we use Odoo as it ships.

When a genuinely special requirement arrives → we extend deliberately, not via "preemptive flexibility."

Code Review — Challenge Every Abstraction

In review, anytime we see an interface, factory, manager, or generic utility, we ask:

  • Is there a second implementation?
  • If not, is the abstraction necessary right now?
  • Can we delete it?

Often the answer is "yes, delete." Smaller codebase, easier to maintain.

Documentation — Keep a Decision Log

Every time we decide not to build something, we write down the reason.

"Not adding multi-currency — client operates one Thai entity; revisit when an overseas subsidiary is on the roadmap."

This document means:

  • Six months later, no one is confused about why a feature is missing
  • When the requirement changes, we can revisit with full context
  • The client trusts the team is thinking deliberately, not forgetting

Case Study — Choosing "Not Yet" Over "Just In Case"

(Details and numbers slightly altered to protect the client.)

ERP project for an import/export trading business. Initial scope: 6 months.

The requirements document used the phrase "may need to support in the future" 14 times.

  • May need multi-currency
  • May need subsidiaries
  • May need to integrate with accounting systems A, B, C
  • May need marketplace sales channels
  • ...

A previous team had proposed quoting for "all of it just in case" — 14 months, ~3× the cost.

We proposed a different approach:

  • Phase 1 (4 months) — a system usable today: single currency, single entity, integration with the one accounting system that's actually in use
  • Phase 2 (on demand) — extend based on real signals, not speculation

The client picked phase 1. Within 4 months the system was live, paying back from cash flow.

After 8 months in production:

  • 3 of the 14 "may need to support" items → genuinely needed → built in phase 2
  • 11 items → never needed, never wanted, or the requirement had changed entirely

If we'd built what the previous team proposed, 11 of 14 features = wasted work = the client paying ~3× for things they wouldn't use.

This is YAGNI as a business decision.


YAGNI in the AI / LLM Era — More Important Than Ever

In 2026, teams write code with AI tooling (Claude Code, Cursor, Codex) 3–5× faster.

But "faster" doesn't mean "should write more."

AI loves to add "just in case" abstractions — because its training data is the global corpus of over-engineered code.

If a team has no YAGNI discipline and lets AI generate freely, the codebase grows 3–5× in the same wall-clock time.

Cost of carry doesn't just grow — it mushrooms.

That's exactly why YAGNI matters more in the AI era. The economics of speculative writing approach zero (AI takes the labor), but the economics of speculative maintenance go up (because there's more code to maintain).

Teams using AI well are teams using AI to write the necessary code as cleanly as possible — not teams using AI to write the most code.


Conclusion — YAGNI Is Discipline, Not a Slogan

YAGNI is not an excuse for laziness, and it's not permission to skip thinking ahead.

YAGNI is a discipline that forces you to:

  • Justify necessity before you write code
  • Cut complexity that doesn't pay off
  • Keep the codebase small, clean, and maintainable
  • Deliver value for every baht the client pays (or every hour you invest)

Fowler's four costs:

  • Build — written but never used
  • Delay — missed shipping what's actually needed
  • Carry — paid every day in maintenance and onboarding
  • Repair — fixed at the moment of truth because the speculation was off

One rule avoids all four — "You Aren't Gonna Need It."

In an AI era where everyone writes code faster, YAGNI matters more. The team that "speculates for free" is the team that pays the most to maintain what got speculated.

At Enersys, we pick this discipline on every project — because clients pay for outcomes, not for clever abstractions.


Sources

"Empowering Innovation,
Transforming Futures."

ติดต่อเราเพื่อทำให้โปรเจกต์ของคุณเป็นจริง