Skip to content

Latest commit

 

History

History
47 lines (37 loc) · 3.71 KB

File metadata and controls

47 lines (37 loc) · 3.71 KB

OBEY Clean Code by Robert C. Martin

When to use

Use when readability, local reasoning, and maintainable code shape are the main concerns, especially during everyday implementation and review.

Primary bias to correct

Working code is not automatically clean code.

Decision rules

  • Treat cleanliness as part of delivery. Preserve behavior, leave touched code cleaner within scope, and do not add mess because the schedule is tight or a rewrite is promised.
  • Write for local reasoning. A reader should understand the path without reconstructing hidden state, wide jumps, or naming trivia.
  • Use precise names and one term per concept. Rename code when vocabulary hides intent, overloads meaning, or forces comments to compensate.
  • Keep functions small, focused, and at one level of abstraction. Tell the story top-down so intent appears before detail.
  • Keep parameters few and meaningful. Avoid boolean flags, output parameters, and grab-bag argument lists; model the concept instead.
  • Separate commands from queries and eliminate hidden side effects. A function that answers should not also mutate behind the reader's back.
  • Keep the happy path readable. Isolate error handling, invalid-state handling, and cleanup; prefer explicit optionality or typed results over null-like sentinel flow when the language supports it.
  • Expose behavior rather than raw representation. Avoid train-wreck access, utility dumping grounds, and classes or modules with mixed responsibilities.
  • Keep construction, framework, persistence, transaction, security, and vendor details outside business behavior.
  • Make public APIs small, explicit, and hard to misuse. Encode boundary logic, required order, and likely changes where readers can see them.
  • Use comments only for rationale, constraints, warnings, or external contracts. Do not narrate code instead of improving it.
  • Treat tests as production code: readable, deterministic, aligned with the behavior or contract they protect, and backed by proportionate validation before calling the change done.
  • Let design emerge through tests, duplication removal, expressiveness, and minimal structure; do not add needless abstractions or infrastructure.
  • When touching code, remove the smell that most increases change cost, but do not silently broaden the task beyond the smallest cleanup that makes the requested change safe.

Trigger rules

  • When a function mixes setup, validation, computation, and side effects, split the phases.
  • When a comment explains control flow, simplify names or structure before keeping the comment.
  • When a function both mutates and answers, or hides a mode switch behind a flag, separate the responsibilities.
  • When duplication, repeated switches, or primitive clusters appear, name the concept with an argument object, polymorphism, special case, or other small abstraction.
  • When a boundary leaks framework, vendor, or persistence quirks inward, add or strengthen a local adapter.
  • When async or concurrency enters, isolate threading policy, minimize shared mutable state, define shutdown, and test timing-sensitive behavior.
  • When fixing a bug or changing behavior, add or update the test that protects the intended contract.
  • When cleanup starts spreading into unrelated areas, cut back to the smallest refactor that keeps the requested change safe and readable.

Final checklist

  • Can a reader follow the change locally?
  • Are names and APIs carrying the meaning without narration?
  • Is mutation explicit and the happy path still clear?
  • Did framework, persistence, vendor, and construction details stay behind boundaries?
  • Did I remove at least one smell from the touched area?
  • Do tests protect the changed behavior or contract?
  • Did I actually run the relevant tests or checks for this change?