- Do not invent requirements. If the user, product docs, or existing code contract did not ask for it, do not build it.
- First find the domain meaning. Do not design from mechanical implementation details when there is a clearer product concept.
- Do not create a second API when the existing API should simply mean the right thing. Fix the primary abstraction instead of adding wrapper methods beside it.
- Keep the default path focused on the states, data, and behavior the product actually cares about. Exhaustive debug/audit paths must be explicit.
- Keep capability ownership in one place. Consumers should call the owning API, not learn how to re-implement part of its policy.
- Names must describe the domain result, not the implementation step. A bad name is a design bug, not a cosmetic issue.
- Do not turn a simple predicate into a subsystem. A filter filters enumeration; it is not a permission layer, custom error surface, CLI policy engine, or future compatibility hook unless explicitly requested.
- Do not add defensive validation for code we own unless the value crosses a real external boundary. Bad internal consumer code should crash normally.
- Do not add a helper just to name one obvious line. Inline the obvious line and move on.
- Document a new option in the one doc that owns how to use it. Mention it elsewhere only when that mention changes a reader's next action.
- Test the current contract, not the history of a mistake. Do not add regression tests whose only purpose is proving an old bad implementation is gone.
- Before adding any function, doc paragraph, or test case, answer: "What real decision or regression does this protect?" If the answer is vague, delete it.
Created
June 18, 2026 14:46
-
-
Save Radagaisus/dfb61fd2542c958eb445a5cdcad68a98 to your computer and use it in GitHub Desktop.
Anti-Overengineering Rules
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment