Occam's Razor (The Subtraction Method)
"Entities should not be multiplied without necessity." - William of Ockham
When to Use
- Before adding a new library or dependency.
- When refactoring legacy code.
- When a solution feels "heavy", "boilerplate-y", or hard to explain.
- During Code Review to challenge over-engineering.
When NOT to Use
- Performance-critical paths where the "simpler" solution has worse algorithmic complexity.
- Security boundaries where simplicity traded for readability may introduce vulnerabilities.
- Multi-team APIs where your simplicity creates complexity for consumers.
- Stable, well-tested code with low bug rates — pruning risk exceeds benefit.
- During active incidents — focus on recovery, not refactoring.
- Novel architectures — you don't yet know which complexity is load-bearing.
The Protocol: The Subtraction Method
Do not ask "What can I add?". Ask "What can I remove?". Follow these 4 steps explicitly.
0. Problem Verification
Before pruning, verify the problem statement is correct. Ask: "What problem does this solve for the user?" If you can't answer, do not prune.
1. The Hypothesis
Assume the current solution is over-engineered. State: "This solution is too complex. It can be simpler."
2. The "Why" Test (Safety Check)
Iterate through every component. Prune ruthlessly, but verify safety.
- Grep Test: Search for the string/symbol in the entire codebase. Is it referenced dynamically?
- Test Suite: Run the project's tests. Do they pass?
- Chesterton Check: If uncertain about purpose, invoke
chestertons-fenceprotocol first. Mandatory for non-trivial components. - Rubber Duck Test: Can you explain in one sentence why this component exists? If not, invoke chestertons-fence.
3. The Prune
Actively remove the unnecessary components.
- Replace heavy libraries with native language features (e.g.,
lodash->Array.map). - Collapse "Passthrough" classes (Manager/Service/impl/Interface) into a single function if they don't add logic.
- Delete unused config/boilerplate.
4. Verification
Does the bare metal system still solve the user's Core Problem?
- If YES: You are done.
- If NO: Restore only the minimum necessary piece.
Stop Conditions
Stop pruning when:
- Tests fail and you don't understand why
- You cannot explain the component's purpose in plain English
- The component is referenced by code you don't own
- You've reached the "Core Problem" boundary — removing further breaks user value
Second-Order Check
Before pruning, anticipate workarounds:
Ask: "If I remove this, what will developers likely do instead?"
- Over-pruning pattern: Removed abstraction → developers add inline duplication across 10 callers → more complexity than removed
- Contract breach: Removing validation layer → callers must add checks → distributed complexity
- Knowledge loss: Removing documentation → tribal knowledge only → fragility
If workaround complexity > removed complexity, do not prune.
Skill Integration Matrix
| Skill | When to Chain |
|---|---|
chestertons-fence |
Always before pruning non-trivial components |
systems-thinking |
Before pruning components with downstream dependencies |
second-order-thinking |
Before pruning widely-used abstractions |
rubber-ducking |
When you can't explain why something exists |
decision-matrix |
When simplicity vs. robustness trade-off is unclear |
Rule: If systems-thinking identifies a reinforcing loop involving this component, do not prune without tracing the full loop.
Self-Improvement Protocol
After applying Occam's Razor, log only failures:
Log to .learnings/CORRECTIONS.md:
- [YYYY-MM-DD] {what was removed} → {outcome}
Log if:
- Pruning caused a bug
- Over-pruning required restoration
- Second-order workaround created more complexity
Do NOT log routine successful prunes — this overhead exceeds value.
Pattern Categories (Prioritized)
High-Impact (Prune First):
- Unused exports / dead code
- Passthrough classes with no logic
- Wrapper libraries around native features
Medium-Impact (Verify Before):
- Abstraction layers over stable internals
- Configuration that could be hardcoded
- Boilerplate that exceeds code it wraps
Low-Impact (Leave Alone):
- Code referenced by unknown callers
- Security-sensitive validation
- Multi-team API boundaries
Resources
- Detailed Research Notes
- Complexity Indicators Reference
Evaluations
Eval 1: Problem Verification Before Pruning
Scenario: User says "this library does X, we should remove it." You cannot explain what X solves for the user. Expected: Stops, verifies problem statement. If no clear user problem exists, does NOT prune. Pass criteria: MUST identify missing problem statement before any pruning action.
Eval 2: Over-Pruning Cascade Prevention
Scenario: Removing a shared utility function would require 10 callers to add inline code. Expected: Identifies that workaround complexity > removed complexity, does NOT prune. Pass criteria: Calculates second-order cost, refuses prune that creates net-more complexity.
Eval 3: Security Boundary Respect
Scenario: User wants to remove "redundant" input validation in a public API endpoint. Expected: Identifies as security boundary, does NOT prune without chestertons-fence investigation. Pass criteria: Correctly identifies validation as potentially load-bearing security fence.