Clean minimal code
Goal: The reader understands intent in one pass. Every line earns its place.
Core rules
- Name for intent, not mechanism —
calculateInvoiceTotal, notdoStuff. - Functions do one thing — if you need "and" to describe it, split it.
- Prefer pure functions — same inputs → same outputs; push I/O to edges.
- YAGNI — no interfaces, factories, or base classes until the second real use case.
- Delete > comment — remove dead code; git remembers.
- Early return — guard clauses beat nested
ifpyramids. - Data over cleverness — plain objects/structs beat inheritance hierarchies.
Minimize lines (without golfing)
| Instead of | Prefer |
|---|---|
| Wrapper that only forwards one call | Call through directly |
| Config object with 12 optional fields | Required params + one options bag for rare flags |
if (x) { return true } else { return false } |
return x |
| Temporary variable used once | Inline when still readable |
Custom Result type for one call site |
Throw or return union at boundary |
| Comment explaining what | Rename so the code explains what |
Line count is a proxy, not the goal. A 40-line function with clear steps beats five 8-line functions with opaque names.
SOLID (practical subset)
| Principle | Application |
|---|---|
| S Single responsibility | Module changes for one reason |
| O Open/closed | Extend via composition/data, not editing core switches |
| L Liskov | Subtypes honor caller expectations (especially errors) |
| I Interface segregation | Small function types; don't force unused methods |
| D Dependency inversion | Domain depends on interfaces; adapters implement them |
Do not introduce interfaces for single implementations.
Established patterns (prefer these)
- Parse, don't validate at boundaries (Zod/schema in, typed domain inside)
- Repository / gateway only when ≥2 storage backends or heavy test doubles needed
- Command/query split when reads and writes have different scaling needs
- Immutability for shared state; mutate locally in tight loops when profiled
- Explicit errors at boundaries; don't leak stringly-typed errors inward
Refactor pass (after green tests)
Run after real-time-testing is green for the slice:
- Rename until a new reader needs no comments.
- Inline functions called once if names add no clarity.
- Extract only when a block has a reused nameable concept (≥2 call sites or test isolation).
- Remove unused imports, params, and branches.
- Re-run the same test command — still green.
Review checklist
- Can any function lose 30%+ lines without losing behavior?
- Any abstraction with one implementation?
- Any boolean flag parameter that should be two functions?
- Any
any/ untyped escape hatch fixable at the boundary? - Names consistent with the rest of the repo?
Boundaries
- Module/package boundaries →
stable-architecture - Acceptance criteria before coding →
deliverable-first