Clean Code (Robert C. Martin) guide to produce and challenge code that is readable, durable, simple, and consistent. Covers naming, functions, comments, smells, and refactor heuristics. Complements `/solid` (SOLID principles) and `/anti-overengineering` (YAGNI/KISS). Activate during the REFACTOR phase of the TDD cycle and during implementation self-review.
Instalação
Instalar com Codex ou Claude Copie este prompt, cole no Codex, Claude ou outro assistente e deixe que ele revise a página da skill e instale para você.
Clean Code (Robert C. Martin) guide to produce and challenge code that is readable, durable, simple, and consistent. Covers naming, functions, comments, smells, and refactor heuristics. Complements `/solid` (SOLID principles) and `/anti-overengineering` (YAGNI/KISS). Activate during the REFACTOR phase of the TDD cycle and during implementation self-review.
triggers
["clean code","readability","refactor","code smell","naming","intention.?revealing","boy.?scout","function too long","too many arguments","challenge.*code"]
Once the pattern is decided (/anti-overengineering) and responsibilities are placed (/solid), /clean-code makes intent self-evident.
The 5 pillars
1. SOLID Design — delegated to /solid
Activate /solid for SRP, OCP, LSP, ISP, DIP. Mentioned here only as a structuring reminder: clean code rests on well-placed responsibilities.
2. Readability first
"The ratio of time spent reading to writing code is well over 10:1. We are constantly reading old code as part of the effort to write new code." — Robert C. Martin
Naming (chap. 2)
Intention-revealing: the name should be enough to understand. If you write a comment to explain, the name is broken.
OK daysSinceLastReview — KO d, days, elapsed
OK filterMergedPullRequests(prs) — KO processPrs(prs, true)
No disinformation: accountList must be a List, otherwise accounts.
Perceptible distinction: getActiveAccount() vs getActiveAccounts() is a time bomb. Prefer getCurrentAccount() vs getAllActiveAccounts().
Searchable: short names only for short scopes (loop index = index in a 3-line loop — not i even though short).
No encoding: no Hungarian notation (strName, bIsActive), no I prefix for interfaces.
No flag arguments: render(isPublic: true) → renderPublic() + renderPrivate().
No hidden side effects: a function named checkPassword(user, password) that ALSO resets the session is a trap.
Command-Query Separation: either the function modifies state, or it returns info. Not both.
Prefer exceptions to error codes: for invariants, throw a typed BusinessRuleViolation. No return null or return { error: ... } smuggled as control flow. Use discriminated unions ({ status: 'success' | 'failed' }) for expected outcomes (cf. coding-standards.md § Error Typing).
Comments (chap. 4)
"The proper use of comments is to compensate for our failure to express ourself in code." — Martin
Project rule (CLAUDE.md): zero comments except if vital. Self-documenting code first.
Code rephrased in prose (// fetch the user above const user = ...)
Formatting (chap. 5)
Variables close to their usage: no grouped declarations at the top of a function.
Newspaper metaphor: top of the file = overview (main exports), bottom = details (private helpers).
Top-down readability: calling functions above called functions.
3. Sustainable quality
"Leave the campground cleaner than you found it." — Boy Scout Rule
Boy Scout Rule: each touched file should be slightly cleaner. Renaming a confusing variable adjacent to the diff scope = OK. Out-of-scope structural refactor = NO (cf. scope-discipline.md).
TDD as quality guard rail: refactor ONLY with green tests. If no tests cover the touched area, write a characterization test before.
Method manipulates more attributes of another class than its own
Move the method
G15 Selector Arguments
Booleans/enums that choose a behavior
Split into multiple functions
G20 Function Names Should Say What They Do
Must read the body to know
Rename
G23 Prefer Polymorphism to If/Else Chains
Switch on a type
Polymorphism or mapping object
G28 Encapsulate Conditionals
if (a && !b && c.isExpired())
Extract as if (shouldRemove(x))
G30 One Thing
"This function does X and Y"
Split
G34 One Level of Abstraction
Mix orchestration + detail
Extract the detail
G35 Magic Numbers
if (count > 7)
Named constant MAX_RETRIES
4. Simplicity
Delegated to /anti-overengineering: YAGNI, KISS, do not anticipate hypothetical business.
Clean Code side-effects:
No "just in case" parameters. A function has only the parameters it needs now.
No dead code: if a function is no longer called, delete it. git log is the history.
No speculative abstraction (AbstractBaseFactoryProvider) for a single use case.
5. Consistency
One convention per context: if the module uses entitiesById: Record<id, Entity>, the neighbor should too. No mixing Map<id, Entity> in the same Bounded Context.
Project patterns to respect (cf. coding-standards.md):
Gateway = interface (port) in entities/ + impl (adapter) in interface-adapters/gateways/
Use case = class implementing UseCase<Input, Output> interface
Controller = transforms inbound events into use case calls, no business logic
Presenter = pure function (domainData) => viewModel
View = Humble Object (zero logic, render only)
Factory usage: factories in src/tests/factories/ are mandatory for test data. Never hardcoded.