Simplicity over Cleverness
Prefer the boring solution everyone understands.
Overview
Clever code impresses once and confuses forever. We choose the simplest design that solves the real problem and reach for complexity only when it earns its keep.
Why
The expensive complexity is rarely clever code. It is machinery introduced to manage coupling that does not exist yet, a registry for components that never reference each other, a configuration surface for a need nobody can describe, a diagnostic for failures nobody has hit. It is hard to resist because it is always added for a good reason, and the reason is always about the future. So the discipline is not "write simpler code". It is being willing to produce a written decision and no code at all, and to say precisely what would change the answer.
Standard
Choose the simplest design that solves the problem actually in front of you, and let the next real requirement argue for more. Not building is a legitimate deliverable. When you decline, record what was postponed, why deferring is cheap, and what specific evidence would reopen the question. Do not introduce an abstraction for a single caller. Do not reimplement, in a convenience layer, rules that an authoritative layer already owns. Accept the thinner result instead, and name the correct fix.
What This Forbids
- Machinery that manages coupling which does not yet exist
- A deferral recorded without its reopening criteria
- An abstraction introduced for a single caller
- Re-implementing an authority's rules to make a secondary interface nicer
Examples
- An operator tool with no command registry, no auto-discovery, no middleware and no base class, because all of those manage coupling between many commands, and there were five that never import one another. The cost of adding a command is one folder and one line.
- The same tool orchestrating rather than reimplementing: it invokes the same script an operator would run by hand, so every heavy operation has exactly one implementation.
- A configuration model shrunk from seven derived directories to two, when five of them existed only because a future feature might one day write there.
- A shared package considered and declined, because extracting it would have created a shared dependency on speculation before a second consumer had proved the logic was actually shared.
Counter Examples
- Sampling machinery added ahead of the traffic that would justify it. It was inert at its default setting and carried a design question, which key, deterministic or random, that could not be answered without data. Removed, with the interface acknowledged as a seam worth keeping rather than a feature worth building.
- A diagnostic command sketched across several releases and never built, correctly: it accumulates checks for failures nobody has hit, and each check is a guess about how the system breaks.
- A configuration surface large enough that adopting one small piece of it required declaring dependencies the consumer would never import.
Lessons Learned
- The refusal is often the engineering output. Several pieces of work correctly produced a written decision and no code.
- A deferral without stated reopening criteria is indistinguishable from an oversight six months later, and worse, nobody recognises the triggering evidence when it finally arrives.
- The evidence a deferred decision is waiting for often arrives disguised as something small. One two-line change supplied the evidence an architecture document had been waiting weeks for, and it was noticed only because the criteria had been written down.
- Accepting a slightly worse outcome to avoid a second source of truth is usually the right trade, provided the correct fix is named rather than forgotten.
Learned From
Related Principles· 2
Related Documents· 2
Referenced By· 8
Version History
- v0.1.0
Principle established with placeholder content.
- v0.2.0strengthened
Written from real experience. Extended from code style to design restraint: refusal as a deliverable, and deferrals that carry their own reopening criteria.