OBEY Refactoring by Martin Fowler
Purpose
This repository follows the discipline of Refactoring in the sense of Martin Fowler:
improve the internal structure of code without changing its observable behavior.
All code generation, edits, and reviews must optimize for:
- small behavior-preserving changes
- clearer names and simpler control flow
- lower duplication
- smaller units of responsibility
- explicit movement from bad design toward good design
- steady design improvement as part of daily work
This file is a binding engineering policy: MUST is binding, SHOULD is a strong default, and MUST NOT is forbidden.
Primary Directive
When modifying existing code, do not start by rewriting large areas.
Start by making the next safe structural improvement that makes the desired change easier.
Prefer:
- establish a safety net
- make a preparatory refactoring
- make the functional change
- refactor again if needed
Reject changes that bundle large functional changes with unrelated structural churn.
What Counts as Refactoring
Refactoring here means:
- changing structure without changing external behavior
- applying small, composable transformations
- removing code smells before or during feature work
- making the next change easier
- improving readability, locality, and testability
Refactoring here does not mean:
- large rewrites
- unverified cleanup
- “modernization” with unclear behavioral impact
- renaming everything at once
- mixing architecture migration, feature work, and cleanup in one uncontrolled patch
Non-Negotiable Rules
Preserve Behavior
- Refactorings must preserve observable behavior.
- If behavior must change, isolate the behavior change from structural refactoring.
- Never disguise a feature change as a refactoring.
Work in Small Steps
- Prefer many small safe edits over one large transformation.
- Each step should be understandable and reversible.
- If a patch feels too large to reason about locally, split it.
Keep the System Running
- Do not leave code in a broken intermediate state unless explicitly asked for a draft.
- Every refactoring sequence should maintain a runnable, buildable state where practical.
Refactor Before and After Feature Work
- If code is hard to change, first reshape it.
- After the feature lands, clean remaining structural debt introduced by the change.
Use the Simplest Helpful Refactoring
- Do not introduce patterns or abstractions earlier than needed.
- Prefer local simplification before large-scale abstraction.
Safety Rules
Tests and Verification
- Create or identify a safety net before risky refactoring.
- Prefer characterization tests when working on unclear existing behavior.
- If tests are absent, make the smallest changes possible and improve testability first.
- Keep refactoring and test updates aligned with preserved behavior.
- Never delete a failing test just to complete a refactoring.
Commit and Patch Discipline
- Separate structural edits from behavior changes whenever practical.
- Group related refactorings together.
- Avoid giant mixed commits that rename, move, redesign, and change logic all at once.
- Prefer reviewable sequences of transformations.
Preparatory Refactoring
Before implementing a feature, ask:
- what makes this change awkward?
- what local structural change would make it straightforward?
- can I rename, extract, move, split, or inline first?
Do the preparatory refactoring before the feature change.
Code Smell Policy
When modifying code, actively look for these smells.
Duplicated Code
- Duplicate logic is a default target for elimination.
- Remove duplication by extracting shared behavior, not by introducing vague utility dumping grounds.
- Do not abstract coincidental similarity.
Long Functions
- Split long functions when they mix responsibilities, levels of abstraction, or phases of work.
- Extract meaningful chunks with names that explain intent.
- Do not create micro-method noise with no explanatory value.
Long Parameter Lists
- Replace repeated clumps with parameter objects or richer domain objects where appropriate.
- Remove boolean flags that switch behavior.
- Avoid signatures that require callers to memorize argument order.
Global Data and Hidden Dependencies
- Reduce reliance on globals, singletons, and ambient context.
- Make dependencies explicit where possible.
- Refactor toward injection, parameters, or clear ownership.
Divergent Change
- If one class changes for many different reasons, split responsibilities.
- Separate business logic, formatting, transport, persistence, and integration concerns.
Shotgun Surgery
- If one change forces edits across many files, centralize the knowledge.
- Introduce a better boundary or clearer ownership.
Feature Envy
- If a method mostly manipulates another object's data, move it or reshape the model.
- Put behavior near the data or concept it belongs to.
Data Clumps and Primitive Obsession
- Replace repeated primitive bundles with meaningful types.
- Give recurring business concepts names and validation.
Switch Statements and Conditionals
- Reduce repeated branching on type or mode when polymorphism, tables, strategies, or better data structures fit.
- Do not replace a single honest conditional with needless indirection.
Temporary Fields and Weird Lifecycles
- Remove fields that exist only for unusual code paths when a separate object or clearer phase model is better.
- Prefer modeling states explicitly over half-initialized objects.
Middle Man and Speculative Generality
- Remove forwarding layers that add no value.
- Delete abstractions created “just in case” if they are not earning their keep.
Preferred Refactoring Moves
Naming Refactorings
- Rename variables to reveal intent.
- Rename functions to describe behavior, not mechanism.
- Rename types and modules to align with problem-domain terminology.
- Rename before deeper refactoring when bad names block understanding.
Extraction Refactorings
- Extract function when a block has a coherent purpose.
- Extract variable when an expression is hard to read.
- Extract class when one class has multiple reasons to change.
- Extract module when a file mixes unrelated concerns.
Movement Refactorings
- Move function to the module or type where the data or concept lives.
- Move field when ownership is clearer elsewhere.
- Move statements to group related operations and reduce cognitive jumps.
Simplification Refactorings
- Inline accidental abstractions.
- Collapse unnecessary layers.
- Replace nested conditionals with guard clauses where it improves clarity.
- Consolidate duplicate conditional fragments.
Data Refactorings
- Encapsulate mutable state.
- Replace magic values with named constants or domain types.
- Introduce parameter objects for repeated argument groups.
- Replace raw collections with named abstractions when behavior accumulates around them.
Refactoring Catalog Index
Composing Methods
- USE Extract Method when a code fragment has a coherent purpose and a useful name.
- USE Inline Method when a method body is clearer than its indirection.
- USE Inline Temp when a temporary variable obscures a direct expression.
- USE Replace Temp with Query when a calculated value deserves a named query and can be reused safely.
- USE Introduce Explaining Variable when a complex expression needs named parts.
- USE Split Temporary Variable when one variable carries multiple meanings.
- USE Remove Assignments to Parameters when parameter mutation obscures input meaning.
- USE Replace Method with Method Object when local state prevents clean extraction.
- USE Substitute Algorithm when a clearer algorithm can replace a tangled one without changing behavior.
Moving Features
- USE Move Method or Move Field when behavior or state belongs more naturally to another object.
- USE Extract Class when one class has more than one reason to change.
- USE Inline Class when a class no longer earns its existence.
- USE Hide Delegate when clients know too much about an object's collaborator.
- USE Remove Middle Man when a forwarding object no longer hides useful detail.
- USE Introduce Foreign Method only when you cannot edit the class that should own the behavior.
- USE Introduce Local Extension when repeated foreign methods need a local, coherent extension point.
Organizing Data
- USE Self Encapsulate Field when direct field access blocks flexibility.
- USE Replace Data Value with Object when a primitive carries behavior, validation, or meaning.
- USE Change Value to Reference when identity and shared updates matter.
- USE Change Reference to Value when value semantics simplify ownership.
- USE Replace Array with Object when positions in a collection have names or rules.
- USE Duplicate Observed Data only when UI or framework synchronization forces it; keep synchronization explicit.
- USE Change Unidirectional Association to Bidirectional only when traversal is needed both ways.
- USE Change Bidirectional Association to Unidirectional when one direction is unnecessary coupling.
- USE Encapsulate Collection when external mutation can bypass invariants.
- USE Replace Record with Data Class when raw records need named access and behavior can grow safely.
- USE Replace Type Code with Class, Subclasses, or State/Strategy according to whether behavior varies by type.
- USE Replace Subclass with Fields when subclass variation is only data.
Simplifying Calls and Conditionals
- USE Decompose Conditional, Consolidate Conditional Expression, and Consolidate Duplicate Conditional Fragments to make branching intent visible.
- USE Remove Control Flag when loop or conditional state can be expressed directly.
- USE Replace Nested Conditional with Guard Clauses when it clarifies the normal path.
- USE Replace Conditional with Polymorphism only when repeated type-based behavior justifies it.
- USE Introduce Null Object when repeated null behavior has a stable meaning.
- USE Introduce Assertion when an assumption should be explicit during development.
- USE Rename Method, Add Parameter, Remove Parameter, Parameterize Method, or Replace Parameter with Explicit Methods to make caller intent clearer.
- USE Preserve Whole Object when callers pass several values from the same object.
- USE Replace Parameter with Method when the receiver can obtain the value itself without hidden coupling.
- USE Remove Setting Method when post-construction mutation should not be allowed.
- USE Hide Method when public surface exposes unnecessary operations.
- USE Replace Constructor with Factory Method when creation intent or subtype selection needs a name.
- USE Encapsulate Downcast when callers should not own cast details.
- USE Replace Error Code with Exception or Replace Exception with Test according to the expected failure model.
Generalization and Big Refactorings
- USE Pull Up Field, Pull Up Method, or Pull Up Constructor Body when duplicated superclass behavior is real.
- USE Push Down Method or Push Down Field when only some subclasses need the feature.
- USE Extract Subclass, Extract Superclass, or Extract Interface only when callers or variation points justify them.
- USE Collapse Hierarchy when inheritance no longer adds meaning.
- USE Form Template Method when similar algorithms differ in controlled steps.
- USE Replace Inheritance with Delegation when inheritance couples unrelated responsibilities.
- USE Replace Delegation with Inheritance only when the subtype relationship is genuine and stable.
- USE Tease Apart Inheritance when one hierarchy mixes multiple variation axes.
- USE Convert Procedural Design to Objects when data and behavior need clearer ownership.
- USE Separate Domain from Presentation when UI and policy are tangled.
- USE Extract Hierarchy when several types share behavior with meaningful variation.
Function-Level Rules
- One function should usually perform one coherent task.
- Keep abstraction level consistent inside a function.
- Remove hidden side effects unless the function's purpose is to cause them.
- Prefer guard clauses over deeply nested conditionals when that clarifies the happy path.
- Split phases like parsing, validation, computation, and I/O when they are mixed together.
- Keep variable scope tight.
- Delete dead code rather than comment it out.
Class and Module Rules
- A class or module should have a narrow reason to change.
- Separate policy from presentation, I/O, persistence, and framework details.
- Prefer composition of small focused units over god objects.
- Delete or inline abstractions that no longer pay for themselves.
- Do not create
utils, helpers, or common modules as a default response to duplication.
- Organize modules around concepts and behavior, not leftover convenience.
Rules for Working with Conditionals
- Replace repeated branching on type or status with stronger modeling when useful.
- Use lookup tables for stable mapping logic.
- Replace nested if/else pyramids with guard clauses, extracted predicates, or strategies when that reduces branching complexity.
- Keep explicit conditionals when they are simple and honest.
- Never introduce polymorphism merely to avoid a small local conditional.
Data and Mutation Rules
- Encapsulate mutation.
- Narrow write access to the smallest useful surface.
- Replace ad hoc mutations with intention-revealing operations.
- Remove duplicated update logic by centralizing state transitions.
- Prefer immutable intermediate values when that simplifies reasoning.
Error Handling Rules
- Refactor error handling to make the main path visible.
- Keep cleanup, validation, and recovery logic from drowning core behavior.
- Standardize similar error paths when they duplicate structure.
- Preserve existing error semantics unless intentionally changing behavior.
Review Rules
When reviewing or generating changes, actively look for:
- duplicated logic
- long functions
- long classes
- tangled control flow
- mixed abstraction levels
- feature envy
- shotgun surgery
- divergent change
- pass-through layers
- speculative generality
- hidden side effects
- global state reliance
- code that requires too much context to change safely
Forbidden Patterns
Do not generate or keep these patterns unless explicitly required and justified.
Big-Bang Rewrite
- replacing a working subsystem wholesale to “clean it up”
- rewriting before understanding current behavior
- changing structure and behavior in one giant move
Mixed-Intent Patches
- feature work mixed with huge unrelated renames
- behavior changes hidden inside cleanup
- code motion that makes review impossible
Abstracting Too Early
- introducing interfaces or strategy hierarchies before a second real need appears
- creating common libraries for one caller
- replacing understandable duplication with unclear shared code
Refactoring Theater
- renaming things while deeper design problems remain untouched
- introducing patterns instead of removing complexity
- creating more files, layers, or wrappers without improving changeability
Untested Structural Surgery
- large refactors without any safety net
- “cleanup” on fragile code with no verification strategy
- assuming behavior is obvious when it is not
Code Generation Rules
When asked to modify existing code, use this default order:
- understand current behavior
- identify the friction for the requested change
- add or improve the safety net if needed
- perform preparatory refactoring
- implement the behavioral change
- perform follow-up cleanup
- stop when the design is clearly better
Preferred first moves:
- rename badly named things
- extract coherent functions
- isolate side effects
- split mixed responsibilities
- move behavior closer to the owning concept
- remove duplication
- simplify conditionals
Preferred avoidance:
- unnecessary framework migrations
- gratuitous API redesign
- large hierarchy introduction
- replacing all old code with new code because the old code is ugly
Testing Rules
- Add characterization tests before risky edits when behavior is unclear.
- Keep tests focused on externally visible behavior.
- Update tests only when behavior intentionally changes.
- Do not couple tests to private implementation details more than necessary.
- Refactor tests too when they become noisy or duplicative.
- Keep test data expressive and minimal.
Stopping Rules
Stop refactoring when:
- the requested change is easy to implement
- the main smells blocking change are removed
- further cleanup would become speculative
- the next abstraction is not yet justified
- readability and local changeability are clearly improved
Review Checklist
Before finalizing any change, verify:
- Did we preserve observable behavior during refactoring?
- Did we separate structural change from behavior change where practical?
- Did we remove at least one real source of friction?
- Is the code easier to read than before?
- Is the code easier to test or change than before?
- Did we reduce duplication or accidental complexity?
- Did we avoid speculative abstraction?
- Did we avoid a giant mixed patch?
- Did names improve?
- Did control flow become simpler?
- Did responsibilities become clearer?
If any answer is no, revise before shipping.
Final Instruction
When uncertain, choose the next small, behavior-preserving transformation
that makes the requested change easier and the code easier to understand.
Reject approaches that gamble on large rewrites or mix too many intentions at once.
1---2name: book-refactoring-full3description: Refactoring (Martin Fowler) — Full rules — comprehensive mandatory coding standards. Use when asked to apply Refactoring principles or review code against Refactoring standards.4license: MIT5---6
7# OBEY Refactoring by Martin Fowler
8
9## Purpose
10
11This repository follows the discipline of **Refactoring** in the sense of Martin Fowler:
12improve the internal structure of code **without changing its observable behavior**.
13
14All code generation, edits, and reviews must optimize for:
15- small behavior-preserving changes
16- clearer names and simpler control flow
17- lower duplication
18- smaller units of responsibility
19- explicit movement from bad design toward good design
20- steady design improvement as part of daily work
21
22This file is a binding engineering policy: `MUST` is binding, `SHOULD` is a strong default, and `MUST NOT` is forbidden.
23
24---
25
26## Primary Directive
27
28When modifying existing code, do **not** start by rewriting large areas.
29Start by making the next safe structural improvement that makes the desired change easier.
30
31Prefer:
321. establish a safety net
332. make a preparatory refactoring
343. make the functional change
354. refactor again if needed
36
37Reject changes that bundle large functional changes with unrelated structural churn.
38
39---
40
41## What Counts as Refactoring
42
43Refactoring here means:
44- changing structure without changing external behavior
45- applying small, composable transformations
46- removing code smells before or during feature work
47- making the next change easier
48- improving readability, locality, and testability
49
50Refactoring here does **not** mean:
51- large rewrites
52- unverified cleanup
53- “modernization” with unclear behavioral impact
54- renaming everything at once
55- mixing architecture migration, feature work, and cleanup in one uncontrolled patch
56
57---
58
59## Non-Negotiable Rules
60
611. **Preserve Behavior**
62 - Refactorings must preserve observable behavior.
63 - If behavior must change, isolate the behavior change from structural refactoring.
64 - Never disguise a feature change as a refactoring.
65
662. **Work in Small Steps**
67 - Prefer many small safe edits over one large transformation.
68 - Each step should be understandable and reversible.
69 - If a patch feels too large to reason about locally, split it.
70
713. **Keep the System Running**
72 - Do not leave code in a broken intermediate state unless explicitly asked for a draft.
73 - Every refactoring sequence should maintain a runnable, buildable state where practical.
74
754. **Refactor Before and After Feature Work**
76 - If code is hard to change, first reshape it.
77 - After the feature lands, clean remaining structural debt introduced by the change.
78
795. **Use the Simplest Helpful Refactoring**
80 - Do not introduce patterns or abstractions earlier than needed.
81 - Prefer local simplification before large-scale abstraction.
82
83---
84
85## Safety Rules
86
87### Tests and Verification
881. Create or identify a safety net before risky refactoring.
892. Prefer characterization tests when working on unclear existing behavior.
903. If tests are absent, make the smallest changes possible and improve testability first.
914. Keep refactoring and test updates aligned with preserved behavior.
925. Never delete a failing test just to complete a refactoring.
93
94### Commit and Patch Discipline
951. Separate structural edits from behavior changes whenever practical.
962. Group related refactorings together.
973. Avoid giant mixed commits that rename, move, redesign, and change logic all at once.
984. Prefer reviewable sequences of transformations.
99
100### Preparatory Refactoring
101Before implementing a feature, ask:
102- what makes this change awkward?
103- what local structural change would make it straightforward?
104- can I rename, extract, move, split, or inline first?
105
106Do the preparatory refactoring before the feature change.
107
108---
109
110## Code Smell Policy
111
112When modifying code, actively look for these smells.
113
114### Duplicated Code
115- Duplicate logic is a default target for elimination.
116- Remove duplication by extracting shared behavior, not by introducing vague utility dumping grounds.
117- Do not abstract coincidental similarity.
118
119### Long Functions
120- Split long functions when they mix responsibilities, levels of abstraction, or phases of work.
121- Extract meaningful chunks with names that explain intent.
122- Do not create micro-method noise with no explanatory value.
123
124### Long Parameter Lists
125- Replace repeated clumps with parameter objects or richer domain objects where appropriate.
126- Remove boolean flags that switch behavior.
127- Avoid signatures that require callers to memorize argument order.
128
129### Global Data and Hidden Dependencies
130- Reduce reliance on globals, singletons, and ambient context.
131- Make dependencies explicit where possible.
132- Refactor toward injection, parameters, or clear ownership.
133
134### Divergent Change
135- If one class changes for many different reasons, split responsibilities.
136- Separate business logic, formatting, transport, persistence, and integration concerns.
137
138### Shotgun Surgery
139- If one change forces edits across many files, centralize the knowledge.
140- Introduce a better boundary or clearer ownership.
141
142### Feature Envy
143- If a method mostly manipulates another object's data, move it or reshape the model.
144- Put behavior near the data or concept it belongs to.
145
146### Data Clumps and Primitive Obsession
147- Replace repeated primitive bundles with meaningful types.
148- Give recurring business concepts names and validation.
149
150### Switch Statements and Conditionals
151- Reduce repeated branching on type or mode when polymorphism, tables, strategies, or better data structures fit.
152- Do not replace a single honest conditional with needless indirection.
153
154### Temporary Fields and Weird Lifecycles
155- Remove fields that exist only for unusual code paths when a separate object or clearer phase model is better.
156- Prefer modeling states explicitly over half-initialized objects.
157
158### Middle Man and Speculative Generality
159- Remove forwarding layers that add no value.
160- Delete abstractions created “just in case” if they are not earning their keep.
161
162---
163
164## Preferred Refactoring Moves
165
166### Naming Refactorings
167- Rename variables to reveal intent.
168- Rename functions to describe behavior, not mechanism.
169- Rename types and modules to align with problem-domain terminology.
170- Rename before deeper refactoring when bad names block understanding.
171
172### Extraction Refactorings
173- Extract function when a block has a coherent purpose.
174- Extract variable when an expression is hard to read.
175- Extract class when one class has multiple reasons to change.
176- Extract module when a file mixes unrelated concerns.
177
178### Movement Refactorings
179- Move function to the module or type where the data or concept lives.
180- Move field when ownership is clearer elsewhere.
181- Move statements to group related operations and reduce cognitive jumps.
182
183### Simplification Refactorings
184- Inline accidental abstractions.
185- Collapse unnecessary layers.
186- Replace nested conditionals with guard clauses where it improves clarity.
187- Consolidate duplicate conditional fragments.
188
189### Data Refactorings
190- Encapsulate mutable state.
191- Replace magic values with named constants or domain types.
192- Introduce parameter objects for repeated argument groups.
193- Replace raw collections with named abstractions when behavior accumulates around them.
194
195---
196
197## Refactoring Catalog Index
198
199### Composing Methods
200- USE Extract Method when a code fragment has a coherent purpose and a useful name.
201- USE Inline Method when a method body is clearer than its indirection.
202- USE Inline Temp when a temporary variable obscures a direct expression.
203- USE Replace Temp with Query when a calculated value deserves a named query and can be reused safely.
204- USE Introduce Explaining Variable when a complex expression needs named parts.
205- USE Split Temporary Variable when one variable carries multiple meanings.
206- USE Remove Assignments to Parameters when parameter mutation obscures input meaning.
207- USE Replace Method with Method Object when local state prevents clean extraction.
208- USE Substitute Algorithm when a clearer algorithm can replace a tangled one without changing behavior.
209
210### Moving Features
211- USE Move Method or Move Field when behavior or state belongs more naturally to another object.
212- USE Extract Class when one class has more than one reason to change.
213- USE Inline Class when a class no longer earns its existence.
214- USE Hide Delegate when clients know too much about an object's collaborator.
215- USE Remove Middle Man when a forwarding object no longer hides useful detail.
216- USE Introduce Foreign Method only when you cannot edit the class that should own the behavior.
217- USE Introduce Local Extension when repeated foreign methods need a local, coherent extension point.
218
219### Organizing Data
220- USE Self Encapsulate Field when direct field access blocks flexibility.
221- USE Replace Data Value with Object when a primitive carries behavior, validation, or meaning.
222- USE Change Value to Reference when identity and shared updates matter.
223- USE Change Reference to Value when value semantics simplify ownership.
224- USE Replace Array with Object when positions in a collection have names or rules.
225- USE Duplicate Observed Data only when UI or framework synchronization forces it; keep synchronization explicit.
226- USE Change Unidirectional Association to Bidirectional only when traversal is needed both ways.
227- USE Change Bidirectional Association to Unidirectional when one direction is unnecessary coupling.
228- USE Encapsulate Collection when external mutation can bypass invariants.
229- USE Replace Record with Data Class when raw records need named access and behavior can grow safely.
230- USE Replace Type Code with Class, Subclasses, or State/Strategy according to whether behavior varies by type.
231- USE Replace Subclass with Fields when subclass variation is only data.
232
233### Simplifying Calls and Conditionals
234- USE Decompose Conditional, Consolidate Conditional Expression, and Consolidate Duplicate Conditional Fragments to make branching intent visible.
235- USE Remove Control Flag when loop or conditional state can be expressed directly.
236- USE Replace Nested Conditional with Guard Clauses when it clarifies the normal path.
237- USE Replace Conditional with Polymorphism only when repeated type-based behavior justifies it.
238- USE Introduce Null Object when repeated null behavior has a stable meaning.
239- USE Introduce Assertion when an assumption should be explicit during development.
240- USE Rename Method, Add Parameter, Remove Parameter, Parameterize Method, or Replace Parameter with Explicit Methods to make caller intent clearer.
241- USE Preserve Whole Object when callers pass several values from the same object.
242- USE Replace Parameter with Method when the receiver can obtain the value itself without hidden coupling.
243- USE Remove Setting Method when post-construction mutation should not be allowed.
244- USE Hide Method when public surface exposes unnecessary operations.
245- USE Replace Constructor with Factory Method when creation intent or subtype selection needs a name.
246- USE Encapsulate Downcast when callers should not own cast details.
247- USE Replace Error Code with Exception or Replace Exception with Test according to the expected failure model.
248
249### Generalization and Big Refactorings
250- USE Pull Up Field, Pull Up Method, or Pull Up Constructor Body when duplicated superclass behavior is real.
251- USE Push Down Method or Push Down Field when only some subclasses need the feature.
252- USE Extract Subclass, Extract Superclass, or Extract Interface only when callers or variation points justify them.
253- USE Collapse Hierarchy when inheritance no longer adds meaning.
254- USE Form Template Method when similar algorithms differ in controlled steps.
255- USE Replace Inheritance with Delegation when inheritance couples unrelated responsibilities.
256- USE Replace Delegation with Inheritance only when the subtype relationship is genuine and stable.
257- USE Tease Apart Inheritance when one hierarchy mixes multiple variation axes.
258- USE Convert Procedural Design to Objects when data and behavior need clearer ownership.
259- USE Separate Domain from Presentation when UI and policy are tangled.
260- USE Extract Hierarchy when several types share behavior with meaningful variation.
261
262---
263
264## Function-Level Rules
265
2661. One function should usually perform one coherent task.
2672. Keep abstraction level consistent inside a function.
2683. Remove hidden side effects unless the function's purpose is to cause them.
2694. Prefer guard clauses over deeply nested conditionals when that clarifies the happy path.
2705. Split phases like parsing, validation, computation, and I/O when they are mixed together.
2716. Keep variable scope tight.
2727. Delete dead code rather than comment it out.
273
274---
275
276## Class and Module Rules
277
2781. A class or module should have a narrow reason to change.
2792. Separate policy from presentation, I/O, persistence, and framework details.
2803. Prefer composition of small focused units over god objects.
2814. Delete or inline abstractions that no longer pay for themselves.
2825. Do not create `utils`, `helpers`, or `common` modules as a default response to duplication.
2836. Organize modules around concepts and behavior, not leftover convenience.
284
285---
286
287## Rules for Working with Conditionals
288
2891. Replace repeated branching on type or status with stronger modeling when useful.
2902. Use lookup tables for stable mapping logic.
2913. Replace nested if/else pyramids with guard clauses, extracted predicates, or strategies when that reduces branching complexity.
2924. Keep explicit conditionals when they are simple and honest.
2935. Never introduce polymorphism merely to avoid a small local conditional.
294
295---
296
297## Data and Mutation Rules
298
2991. Encapsulate mutation.
3002. Narrow write access to the smallest useful surface.
3013. Replace ad hoc mutations with intention-revealing operations.
3024. Remove duplicated update logic by centralizing state transitions.
3035. Prefer immutable intermediate values when that simplifies reasoning.
304
305---
306
307## Error Handling Rules
308
3091. Refactor error handling to make the main path visible.
3102. Keep cleanup, validation, and recovery logic from drowning core behavior.
3113. Standardize similar error paths when they duplicate structure.
3124. Preserve existing error semantics unless intentionally changing behavior.
313
314---
315
316## Review Rules
317
318When reviewing or generating changes, actively look for:
319- duplicated logic
320- long functions
321- long classes
322- tangled control flow
323- mixed abstraction levels
324- feature envy
325- shotgun surgery
326- divergent change
327- pass-through layers
328- speculative generality
329- hidden side effects
330- global state reliance
331- code that requires too much context to change safely
332
333---
334
335## Forbidden Patterns
336
337Do not generate or keep these patterns unless explicitly required and justified.
338
339### Big-Bang Rewrite
340- replacing a working subsystem wholesale to “clean it up”
341- rewriting before understanding current behavior
342- changing structure and behavior in one giant move
343
344### Mixed-Intent Patches
345- feature work mixed with huge unrelated renames
346- behavior changes hidden inside cleanup
347- code motion that makes review impossible
348
349### Abstracting Too Early
350- introducing interfaces or strategy hierarchies before a second real need appears
351- creating common libraries for one caller
352- replacing understandable duplication with unclear shared code
353
354### Refactoring Theater
355- renaming things while deeper design problems remain untouched
356- introducing patterns instead of removing complexity
357- creating more files, layers, or wrappers without improving changeability
358
359### Untested Structural Surgery
360- large refactors without any safety net
361- “cleanup” on fragile code with no verification strategy
362- assuming behavior is obvious when it is not
363
364---
365
366## Code Generation Rules
367
368When asked to modify existing code, use this default order:
3691. understand current behavior
3702. identify the friction for the requested change
3713. add or improve the safety net if needed
3724. perform preparatory refactoring
3735. implement the behavioral change
3746. perform follow-up cleanup
3757. stop when the design is clearly better
376
377Preferred first moves:
378- rename badly named things
379- extract coherent functions
380- isolate side effects
381- split mixed responsibilities
382- move behavior closer to the owning concept
383- remove duplication
384- simplify conditionals
385
386Preferred avoidance:
387- unnecessary framework migrations
388- gratuitous API redesign
389- large hierarchy introduction
390- replacing all old code with new code because the old code is ugly
391
392---
393
394## Testing Rules
395
3961. Add characterization tests before risky edits when behavior is unclear.
3972. Keep tests focused on externally visible behavior.
3983. Update tests only when behavior intentionally changes.
3994. Do not couple tests to private implementation details more than necessary.
4005. Refactor tests too when they become noisy or duplicative.
4016. Keep test data expressive and minimal.
402
403---
404
405## Stopping Rules
406
407Stop refactoring when:
408- the requested change is easy to implement
409- the main smells blocking change are removed
410- further cleanup would become speculative
411- the next abstraction is not yet justified
412- readability and local changeability are clearly improved
413
414---
415
416## Review Checklist
417
418Before finalizing any change, verify:
419- Did we preserve observable behavior during refactoring?
420- Did we separate structural change from behavior change where practical?
421- Did we remove at least one real source of friction?
422- Is the code easier to read than before?
423- Is the code easier to test or change than before?
424- Did we reduce duplication or accidental complexity?
425- Did we avoid speculative abstraction?
426- Did we avoid a giant mixed patch?
427- Did names improve?
428- Did control flow become simpler?
429- Did responsibilities become clearer?
430
431If any answer is no, revise before shipping.
432
433---
434
435## Final Instruction
436
437When uncertain, choose the next **small, behavior-preserving transformation**
438that makes the requested change easier and the code easier to understand.
439Reject approaches that gamble on large rewrites or mix too many intentions at once.