Help us improve
Share bugs, ideas, or general feedback.
From code-craftsmanship
Applies named refactoring transformations to improve code structure without changing behavior. Covers smell-driven refactoring, safe transformation sequences, and testing guards.
npx claudepluginhub wondelai/skills --plugin systems-architectureHow this skill is triggered — by the user, by Claude, or both
Slash command
/code-craftsmanship:refactoring-patternsThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
A disciplined approach to improving the internal structure of existing code without changing its observable behavior. Every refactoring follows the same loop: verify tests pass, apply one small structural change, verify tests still pass.
Applies disciplined refactoring in small, verifiable steps to improve code structure without changing behavior: extract functions, rename, move code.
Guides safe, incremental refactoring to improve code quality without changing behavior. Generates analysis/plans via refactor:analyze/plan commands, covers smells and patterns like Extract Method.
Proven refactoring patterns (Extract Method, Replace Temp, Introduce Parameter Object) to improve code structure safely. Use when improving existing code while keeping behavior unchanged.
Share bugs, ideas, or general feedback.
A disciplined approach to improving the internal structure of existing code without changing its observable behavior. Every refactoring follows the same loop: verify tests pass, apply one small structural change, verify tests still pass.
Refactoring is not rewriting. It is a sequence of small, behavior-preserving transformations, each backed by tests. You never change what the code does — only how it is organized. Big-bang rewrites fail because they combine structural change with behavioral change, making it impossible to know which broke things.
The foundation: Bad code is a natural consequence of delivering under time pressure, not a character flaw. Code smells are objective signals of degraded structure; the smell catalog tells you where to look, and the refactoring catalog tells you what to do.
Goal: 10/10. When reviewing or refactoring code, rate structural quality 0-10: a 10/10 means no obvious smells remain, each function does one thing, names reveal intent, duplication is eliminated, and tests cover the refactored paths. Always give the current score and the specific refactorings needed to reach 10/10.
Six areas of focus for systematically improving code structure:
Core concept: Code smells are surface indicators of deeper structural problems — not bugs, but signals that the design makes code harder to understand, extend, or maintain. Each smell maps to named refactorings that fix it.
Why it works: Named smells give teams objective criteria instead of subjective "I don't like this" — "This is Feature Envy" points directly at the fix.
Key insights:
Code applications:
| Context | Pattern | Example |
|---|---|---|
| Method > 10 lines | Extract Method | Pull loop body into calculateLineTotal() |
| Switch on type code | Replace Conditional with Polymorphism | Subclass per order type |
| Same params in many methods | Introduce Parameter Object | startDate, endDate → DateRange |
| Copy-pasted logic | Extract Method + Pull Up Method | Share via common method or base class |
See: references/smell-catalog.md when you need the full smell-to-refactoring mapping.
Core concept: Most refactoring starts here: break long methods into smaller, well-named pieces that read like prose — high-level steps delegating to clearly named helpers.
Why it works: Short methods with intention-revealing names eliminate comments, make bugs obvious at a glance, and enable reuse; a method call costs nothing to read when the name says everything.
Key insights:
Code applications:
| Context | Pattern | Example |
|---|---|---|
| Block with a comment | Extract Method | // check eligibility → isEligible() |
| Temp used once | Inline Variable | Drop const price = order.getPrice() |
| Trivial delegating method | Inline Method | Inline return deliveries > 5 if used once |
| Method with many tangled locals | Replace Method with Method Object | Locals become fields in a new class |
See: references/composing-methods.md for mechanics and worked examples of each.
Core concept: The key OO design decision is where responsibilities live. When Feature Envy, excessive coupling, or unbalanced class sizes show a method or field is in the wrong class, move it where it belongs.
Why it works: When a method lives with the data it uses, changes affect one class; misplaced methods create invisible dependencies that cause Shotgun Surgery.
Key insights:
Code applications:
| Context | Pattern | Example |
|---|---|---|
| Method envies another class | Move Method | calculateShipping() from Order to ShippingPolicy |
| God class 500+ lines | Extract Class | Pull Address fields/methods into own class |
Client calls a.getB().getC() | Hide Delegate | Add a.getCThroughB() |
| Class only forwards calls | Remove Middle Man | Let client call the delegate directly |
See: references/moving-features.md when deciding where a responsibility belongs.
Core concept: Raw data — magic numbers, exposed fields, integer type codes — creates subtle bugs and scatters domain knowledge. Replace primitives with objects that encapsulate behavior and enforce invariants.
Why it works: An int amount has no rounding rules or currency code; a Money object encapsulates all of it, so business rules live in one place and the type system catches errors at compile time.
Key insights:
EmailAddress, Money, Temperature)Customer, not copies)Code applications:
| Context | Pattern | Example |
|---|---|---|
if (status == 2) | Replace Magic Number | if (status == ORDER_SHIPPED) |
String email passed everywhere | Replace Data Value with Object | EmailAddress class with validation |
| Getter returns mutable list | Encapsulate Collection | Return Collections.unmodifiableList(items) |
int typeCode with switch | Replace Type Code with Subclasses | Employee → Engineer, Manager |
See: references/organizing-data.md for the full data-refactoring catalog.
Core concept: Deeply nested if/else trees, long switches, and scattered null checks are the hardest code to read and the most bug-prone. Named refactorings decompose, consolidate, and replace conditionals with clearer structures.
Why it works: A six-branch conditional forces readers to simulate every path mentally; well-named extracted branches are self-documenting, and polymorphism eliminates whole categories of "forgot this case" bugs.
Key insights:
if (x == null) checks; Introduce Assertion makes assumptions fail fastCode applications:
| Context | Pattern | Example |
|---|---|---|
Long if with complex condition | Decompose Conditional | Extract isSummer(date) and summerCharge() |
Deeply nested if/else | Replace with Guard Clauses | Edge cases first, return early, flat main path |
| Switch on object type | Replace Conditional with Polymorphism | Each type implements its own calculatePay() |
if (customer == null) everywhere | Introduce Special Case | NullCustomer with safe default behavior |
See: references/simplifying-conditionals.md for before/after examples.
Core concept: Refactoring is only safe when wrapped in tests. The workflow is mechanical: run tests (green), apply one small transformation, run tests (green), commit. If tests go red, revert — don't debug a broken refactoring.
Why it works: Small steps make the failure obvious (it was the last thing you did) and reverting costs seconds; debugging a failed big-bang rewrite costs days.
Key insights:
Code applications:
| Context | Pattern | Example |
|---|---|---|
| About to add a feature | Preparatory Refactoring | Clean the insertion point first |
| Third copy of same logic | Rule of Three | Extract shared logic now |
| Large API change in production | Branch by Abstraction | Add abstraction layer, migrate callers, remove old path |
| Renaming a widely-used method | Parallel Change | Add new, deprecate old, migrate, remove |
See: references/refactoring-workflow.md for the full cycle and when-to-refactor guidance.
| Mistake | Why It Fails | Fix |
|---|---|---|
| Refactoring without tests | No safety net to detect behavior change | Write characterization tests first |
| Big-bang rewrite | Mixes structural and behavioral change; undebuggable | Smallest possible steps, tests after each |
| Refactoring while adding features | Two hats at once — neither change verifiable | Refactor first (commit), then add feature (commit) |
| Renaming without updating callers | Broken build or dead code | Use IDE rename; search all references |
| Extracting too many tiny methods | Indirection without clarity when names are poor | Each name must remove the need to read the body |
| Ignoring the smell catalog | Reinvents fixes instead of applying proven recipes | Learn named smells; each maps to refactorings |
| Refactoring doomed code | Polish on condemned code is waste | Check the code's lifespan justifies the investment |
| Optimizing while refactoring | Conflates clarity with performance | Clarity first, then profile, then optimize hot path |
| Question | If No | Action |
|---|---|---|
| Do tests pass before you start? | No safety net | Write or fix tests first — never refactor red |
| Can you name the smell you're fixing? | Refactoring by instinct, not catalog | Identify the smell, apply its prescribed refactoring |
| Is each method under ~10 lines? | Long Methods likely | Extract Method into named steps |
| Does each class have one reason to change? | Divergent Change or Large Class | Extract Class to separate responsibilities |
| Are there duplicated code blocks? | The most expensive smell | Extract shared logic into common method/base class |
| Do conditionals use polymorphism where apt? | Switch Statements remain | Replace Conditional with Polymorphism |
| Are you committing after each step? | Risk losing work, mixing changes | Commit after every green-to-green transformation |
| Is the code easier to read after your change? | Refactoring added complexity | Revert and try a different approach |
The definitive guides to improving existing code:
Martin Fowler is Chief Scientist at Thoughtworks, a signatory of the Agile Manifesto, and author of Refactoring: Improving the Design of Existing Code (1999; 2nd edition 2018), which introduced catalog-based, named refactorings to mainstream development. His catalog underpins the automated refactoring tools in every major IDE.