100%

الدرس 2 من 2

Simplicity Is a Budget: KISS and YAGNI

Complexity you cannot remove and complexity you chose, why "You Aren't Gonna Need It" is about reversibility, and the three categories where applying it will hurt you badly.

قراءة 11 دقيقة

KISS — "keep it simple" — is useless as stated, because nobody sets out to make things complicated. It becomes useful once you separate the complexity that comes from the problem from the complexity you introduced while solving it. Fred Brooks called these essential and accidental complexity, and the distinction is the whole of the principle.

Essential versus accidental complexity

Essential complexity

Complexity that belongs to the problem. Tax rules differ by country. Payments can be reversed months later. Two users can edit the same document at once.

  • Removing it means removing a requirement, which is a business conversation
  • Naming it honestly stops teams blaming the code for the domain
  • It is the part that a rewrite will faithfully reproduce
  • It cannot be engineered away, only contained
  • It sets a floor on how simple the system can be

Choose when: Always name it first. If a system feels complicated, establish how much of that is the domain before proposing any structural change.

Accidental complexity

Complexity introduced by the solution: an unnecessary abstraction, a message queue where a function call would do, four configuration systems, a bespoke framework nobody documented.

  • It can be removed by a team on its own authority
  • Removing it usually improves several quality attributes at once
  • Removing it competes with feature work for the same capacity
  • Some of it is load-bearing by the time you notice it

Choose when: This is the target of every "simplify" effort. If a change would not reduce accidental complexity, it is a preference argument rather than a simplification.

YAGNI: build it when you need it

YAGNI is aimed squarely at the gold-plating failure mode from Chapter 1, and applied to reversible decisions it is close to always right. Applied indiscriminately, it is dangerous — because it says nothing about cost of reversal, which is exactly the variable that Chapter 1 established as the thing architecture is about. The competent version of YAGNI is: *defer decisions that are cheap to make later; make decisions now when making them later is expensive.*

CategoryWhy deferral is expensiveThe minimum to do now
Security and tenancy boundariesRetrofitting isolation means auditing every query and every historical row, and a leak is not undoableDecide the tenancy model and enforce authorisation centrally from day one
Data model and identifiersA changed identity or a lost column means migrating accumulated history, which grows every day you waitGet identifiers, money representation and timestamps right before data accumulates
ObservabilityYou cannot investigate an incident with telemetry you start collecting after itStructured logs with a correlation identifier, and one metric per critical path
Three categories where "we will add it when we need it" reliably fails, because retrofitting is not proportional to the feature.

In practice

Two deferrals, one good and one costly

A B2B analytics startup applied YAGNI deliberately across its first eighteen months and reviewed the results before a funding round.

Constraints

  • Five engineers, pre-revenue for the first nine months
  • Single region, single customer tier at launch
  • Compliance requirements arrived in month fourteen
  • Roughly 200 million rows accumulated by month eighteen

Decision

They deferred multi-region deployment, a plugin system, a public API and role-based permissions beyond admin-or-not. They did not defer per-row tenant attribution, monetary values as integer minor units, or request correlation identifiers in logs.

Why

The deferred items were all additive: multi-region became a deployment project, the public API was built once a customer paid for it, and finer permissions were added in three weeks when the first enterprise customer asked. None of them required touching existing data. The three non-deferred items all had costs that grew with accumulated rows or with the number of code paths, so making them late would have meant migrating history.

What it cost

The permission model they shipped was crude enough that two mid-sized customers had to wait a quarter, which cost one of them. That was a real loss, and it was still cheaper than the alternative they avoided: a team nearby that deferred tenant attribution spent five months backfilling ownership onto 40 million rows with incomplete provenance, and could not fully prove the result. The team's written rule afterwards was "defer features, never defer the shape of the data or who is allowed to see it".

Hearing "let's keep it simple for now"

As a developer

Agrees, and ships the smallest thing that works. Simplicity is a virtue and the deadline is real, so the smallest thing is both the fastest and the most defensible option.

As an architect

Agrees for anything reversible, and asks one question for everything else: if we do this later, is it the same amount of work, or does the work grow with the data and the code we add in the meantime? Growing cost means decide now, even when the simple option is tempting. The architect's contribution is not caution — it is knowing which corner is cheap to cut.

Your team is building an internal tool for one department. Someone proposes skipping authorisation entirely for the first release "because everyone in the department can see everything anyway". Is that a legitimate application of YAGNI?Reveal

No, and the reason is the shape of the future cost rather than any general rule about security. Adding authorisation later means revisiting every read path, every write path and every existing report, and by then the tool will have grown users outside the department who were added informally — so you would also be reconstructing who should have seen what, retroactively, without a record. The proportionate answer is not to build a full role system now; it is to route every access through one central check that currently returns "allowed for department members", so that tightening it later is one function rather than an audit. Deferring the *policy* is fine; deferring the *place where policy is enforced* is what gets expensive.

Key takeaways

  • Separate essential complexity, which belongs to the problem, from accidental complexity, which you introduced.
  • Simple means not intertwined; easy means familiar. Optimise for simple, and expect deadlines to push toward easy.
  • YAGNI is correct for reversible decisions and dangerous for decisions whose later cost grows with data or code.
  • Security boundaries, data-model shape and observability are the three standing exceptions to YAGNI.
  • Where you cannot justify building the capability now, build the single place where it will later be added.
Simplicity Is a Budget: KISS and YAGNI · Architecture Atlas