ワンクリックで
refactoring
Refactoring patterns - improving code design without changing behavior
Codex または Claude でインストール この Prompt をコピーして Codex、Claude、または他のアシスタントに貼り付けると、Skill ページを確認してインストールできます。
メニュー
Refactoring patterns - improving code design without changing behavior
Codex または Claude でインストール この Prompt をコピーして Codex、Claude、または他のアシスタントに貼り付けると、Skill ページを確認してインストールできます。
SOC 職業分類に基づく
Read-only quality scan of components. Reports problems without making changes. Uses software-base + domain profile skills.
Read-only quality scan of components. Reports problems without making changes. Uses software-base + domain profile skills.
Internal phase: independent Codex review + targeted fixes. Not user-facing.
Find duplicated code and consolidate into shared utilities. Fixes all duplicates.
Reference templates for Codex evaluation. Used by build/improve orchestrators — not executed directly.
Hard-ass code review via Gemini. ALL issues must be fixed. No exceptions.
| name | refactoring |
| description | Refactoring patterns - improving code design without changing behavior |
Channel Martin Fowler, Michael Feathers, and Joshua Kerievsky.
"Refactoring is a disciplined technique for restructuring an existing body of code, altering its internal structure without changing its external behavior." — Fowler
The Two Hats:
Never wear both hats at once.
Smell-driven, not pattern-driven. Identify a smell first. Pick the minimum refactoring to fix it. Never scan for opportunities to introduce patterns.
| Smell | Refactoring |
|---|---|
| Long Method | Extract Method, Replace Temp with Query |
| Large Class | Extract Class, Extract Subclass |
| Long Parameter List | Introduce Parameter Object, Preserve Whole Object |
| Data Clumps | Extract Class, Introduce Parameter Object |
| Primitive Obsession | Replace Primitive with Object, Replace Type Code with Class |
| Smell | Refactoring |
|---|---|
| Switch Statements | Replace Conditional with Polymorphism |
| Parallel Inheritance | Move Method, Move Field |
| Lazy Class | Inline Class, Collapse Hierarchy |
| Speculative Generality | Collapse Hierarchy, Inline Class, Remove Parameter |
| Temporary Field | Extract Class, Introduce Null Object |
| Smell | Refactoring |
|---|---|
| Divergent Change | Extract Class |
| Shotgun Surgery | Move Method, Move Field, Inline Class |
| Parallel Inheritance | Move Method, Move Field |
| Smell | Refactoring |
|---|---|
| Comments (as deodorant) | Extract Method, Rename Method |
| Duplicate Code | Extract Method, Pull Up Method, Form Template Method |
| Dead Code | Remove Dead Code |
| Lazy Class | Inline Class |
| Speculative Generality | Collapse Hierarchy, Remove Parameter |
| Smell | Refactoring |
|---|---|
| Feature Envy | Move Method, Extract Method |
| Inappropriate Intimacy | Move Method, Move Field, Hide Delegate |
| Message Chains | Hide Delegate, Extract Method, Move Method |
| Middle Man | Remove Middle Man, Inline Method |
Apply patterns only when a smell justifies the destination. The smell is the trigger — the pattern is the minimum fix.
| Smell | Refactoring to Pattern | Justification Gate |
|---|---|---|
| Repeated conditional on type | Replace Conditional with Strategy | 3+ branches on same discriminator |
| Constructor with many combos | Replace Constructors with Builder | 4+ optional parameters, callers use different subsets |
| Notification spaghetti | Replace Hard-Coded Notifications with Observer | 3+ listeners or listeners change at runtime |
| Embedded algorithm varies | Replace Algorithm with Strategy | 2+ variants exist or are imminent |
| Composite structure with type checks | Replace Implicit Tree with Composite | Recursive structure with uniform operations |
| Accumulating decorations | Replace Layered Behavior with Decorator | Behaviors compose independently |
| State-dependent conditionals | Replace State-Altering Conditionals with State | 3+ states with transition logic spread across methods |
| Complex object creation | Replace Constructor with Factory Method | Creation varies by context or subtype |
When code has no tests, you cannot safely refactor. Use these techniques to get tests in place first.
Write tests that document current behavior, not intended behavior:
Characterization tests are not aspirational. They describe what the code does, not what it should do.
A seam is a place where you can alter behavior without editing the source. Three types:
| Seam Type | How It Works | When to Use |
|---|---|---|
| Object seam | Override method in subclass or pass different implementation | Class with injectable dependency |
| Link seam | Swap module/import at build or test time | Module-level dependency |
| Preprocessing seam | Conditional compilation or feature flags | Build-time variation |
Use these to get legacy code under test:
| Technique | What It Does |
|---|---|
| Extract Interface | Create interface from class to enable substitution |
| Parameterize Constructor | Pass dependency in instead of creating internally |
| Subclass and Override Method | Override the problematic method in a test subclass |
| Extract and Override Call | Move a hard-to-test call into its own method, override in test |
| Replace Global Reference with Getter | Wrap global access in a method you can override |
| Introduce Instance Delegator | Replace static method with instance method that delegates to it |
To refactor safely, you need tests. To add tests, you often need to refactor. Break the deadlock:
// Before
function printOwing() {
printBanner();
// print details
console.log("name: " + name);
console.log("amount: " + getOutstanding());
}
// After
function printOwing() {
printBanner();
printDetails(getOutstanding());
}
function printDetails(outstanding) {
console.log("name: " + name);
console.log("amount: " + outstanding);
}
// Before
function getSpeed() {
switch (this.type) {
case 'european': return getBaseSpeed();
case 'african': return getBaseSpeed() - getLoadFactor() * numberOfCoconuts;
case 'norwegian_blue': return isNailed ? 0 : getBaseSpeed();
}
}
// After
class European extends Bird {
getSpeed() { return this.getBaseSpeed(); }
}
class African extends Bird {
getSpeed() { return this.getBaseSpeed() - this.getLoadFactor() * this.numberOfCoconuts; }
}
class NorwegianBlue extends Bird {
getSpeed() { return this.isNailed ? 0 : this.getBaseSpeed(); }
}
// Before
function amountInvoiced(startDate, endDate) { ... }
function amountReceived(startDate, endDate) { ... }
function amountOverdue(startDate, endDate) { ... }
// After
class DateRange {
constructor(start, end) { this.start = start; this.end = end; }
}
function amountInvoiced(dateRange) { ... }
function amountReceived(dateRange) { ... }
function amountOverdue(dateRange) { ... }
// Before — related code is scattered
const price = order.basePrice;
sendConfirmation(order);
const discount = calculateDiscount(price);
// After — related code is together
const price = order.basePrice;
const discount = calculateDiscount(price);
sendConfirmation(order);
// Before
const result = [];
for (const person of people) {
if (person.age > 18) {
result.push(person.name);
}
}
// After
const result = people
.filter(p => p.age > 18)
.map(p => p.name);
// Before — parsing and calculation interleaved
function priceOrder(product, quantity, shippingMethod) {
const basePrice = product.basePrice * quantity;
const discount = Math.max(quantity - 500, 0) * product.basePrice * 0.05;
const shippingCost = calcShipping();
return basePrice - discount + shippingCost;
}
// After — separated into pricing phase and shipping phase
function priceOrder(product, quantity, shippingMethod) {
const priceData = calculatePricingData(product, quantity);
return applyShipping(priceData, shippingMethod);
}