57 lines
2.9 KiB
Markdown
57 lines
2.9 KiB
Markdown
# Contract: Keep It Simple
|
||
|
||
Version: 1.0
|
||
|
||
## Principle
|
||
|
||
Working solutions do not need to be interesting.
|
||
|
||
Prefer the simplest solution that correctly solves the problem. Complexity must be justified by a real, present requirement — not by anticipation of future needs or desire to use a particular technique.
|
||
|
||
## Rules
|
||
|
||
- Choose boring technology. A well-understood, dull solution beats a clever one.
|
||
- Do not introduce abstractions, patterns, or frameworks before they are needed by at least two concrete use cases.
|
||
- Do not design for hypothetical future requirements. Build for what exists now.
|
||
- Prefer sequential, readable code over clever one-liners.
|
||
- If you can delete code and the system still works, delete it.
|
||
- Extra configurability, generalization, and extensibility are costs, not features. Add them only when explicitly required.
|
||
|
||
## Anti-patterns
|
||
|
||
- Adding helpers or utilities for one-time operations.
|
||
- Wrapping simple logic in interfaces "for testability" when a direct call works.
|
||
- Using a framework or library to solve a problem the standard library already handles.
|
||
- Writing error handling, fallbacks, or validation for scenarios that cannot happen.
|
||
- Refactoring working code because it "could be cleaner."
|
||
|
||
## Bulletproof features
|
||
|
||
A feature must be correct by construction, not by circumstance.
|
||
|
||
Do not write mechanisms that silently rely on:
|
||
- another feature being in a specific state,
|
||
- input data having a particular shape that "usually" holds,
|
||
- a certain call order or timing,
|
||
- a global flag, ambient variable, or external condition being set upstream.
|
||
|
||
Such mechanisms are thin: they work only when the world cooperates. When any surrounding assumption shifts, they break in ways that are hard to trace. This is the primary source of bugs.
|
||
|
||
**Design rules:**
|
||
|
||
- A feature owns its preconditions. If it requires data in a certain state, it must enforce or produce that state itself — not inherit it silently from a caller.
|
||
- Never write logic that only works if a sibling feature runs first and succeeds. If coordination is needed, make it explicit (a parameter, a return value, a clear contract).
|
||
- Avoid implicit state machines — sequences where operations must happen in the right order with no enforcement. Either enforce the order structurally or eliminate the dependency.
|
||
- Prefer thick, unconditional logic over thin conditional chains that assume stable context. A mechanism that always does the right thing is more reliable than one that does the right thing only when conditions are favorable.
|
||
|
||
A feature is done when it is correct on its own, not when it is correct given that everything else is also correct.
|
||
|
||
## Checklist before committing
|
||
|
||
1. Could this be done with fewer lines without losing clarity?
|
||
2. Does every abstraction here have more than one caller?
|
||
3. Is any of this code handling a case that cannot actually occur?
|
||
4. Did I add anything beyond what was asked?
|
||
|
||
If the answer to any of 1–4 is "yes," simplify before committing.
|