Now liveThe Skillselion MCP - thousands of ranked skills, loaded into your agent mid-task. No install.Get it →
smallnest avatar

Refactor

  • 324 installs
  • 199 repo stars
  • Updated July 21, 2026
  • smallnest/goal-workflow

Helps with code review & quality tasks.

About

refactor is a Claude Code skill for code review & quality. It helps solo builders move faster with AI-assisted development.

  • refactor
  • Code Review & Quality
  • AI-coding skill

Refactor by the numbers

  • 324 all-time installs (skills.sh)
  • +42 installs in the week ending Aug 5, 2026 (Skillselion tracking)
  • Ranked #275 of 1,352 Code Review & Quality skills by installs in the Skillselion catalog
  • Data as of Aug 5, 2026 (Skillselion catalog sync)
npx skills add https://github.com/smallnest/goal-workflow --skill refactor

Add your badge

Show developers this skill is listed on Skillselion. Paste this into your README.

Listed on Skillselion
Installs324
repo stars199
Last updatedJuly 21, 2026
Repositorysmallnest/goal-workflow

What it does

Helps with code review & quality tasks.

Files

SKILL.mdMarkdownGitHub ↗

Refactor — Expert Code Restructuring

Surgical code refactoring based on Martin Fowler's <Refactoring> (2nd Edition) catalog. Improve structure, readability, and maintainability without changing external behavior. Gradual evolution, not revolution.

---

When to Use

This skill activates when:

  • Code is hard to understand or maintain
  • Functions/classes have grown too large
  • Code smells are detected
  • Adding features is difficult due to poor structure
  • User explicitly requests refactoring, cleanup, or improvement
  • User says: refactor, 重构, clean up, improve code, code smell, extract method, rename, simplify

---

The Golden Rules

These five rules are non-negotiable. Violating any of them turns refactoring into reckless editing.

1. Behavior is Preserved

Only how the code works changes, never what it does. If tests existed before, they must pass after. If the refactoring introduces a behavioral change, it's not refactoring — it's rewriting.

2. Small Steps

Each change should be the smallest possible transformation that compiles and passes tests. If a step breaks, you know exactly which change caused it. Refactoring is a series of tiny, safe transformations, not one big rewrite.

3. Version Control is Your Friend

Commit before starting. Commit after each successful step. This gives you infinite undo. Branch from a clean state so you can abandon the refactoring without consequences.

4. Tests are Essential

"Without tests, you're not refactoring — you're just editing." If tests don't exist for the target code, write characterization tests first. These tests capture the current behavior so you can detect regressions.

5. One Thing at a Time

Never mix refactoring with feature changes. Never refactor two unrelated things simultaneously. Each commit should contain exactly one refactoring operation.

---

When NOT to Refactor

ScenarioAction
Code works and won't change againLeave it alone
Critical production path with no testsWrite characterization tests first
Under tight deadline pressureDocument the smell, refactor later
No clear purpose or benefitDon't refactor for refactoring's sake
Code is fundamentally wrongThis is a rewrite, not a refactoring

---

Code Smells Catalog

Based on Fowler's taxonomy. Before refactoring, identify which smell is present.

Bloaters

SmellDescriptionPrimary Refactoring
Long MethodMethod > 10-15 lines, doing multiple thingsExtract Method, Replace Temp with Query
Large ClassClass with too many fields/methods (God Object)Extract Class, Extract Subclass
Primitive ObsessionUsing primitives instead of small objectsReplace Data Value with Object, Replace Type Code with Class
Long Parameter ListMethod with > 3-4 parametersIntroduce Parameter Object, Preserve Whole Object
Data ClumpsSame group of data appearing togetherExtract Class, Introduce Parameter Object

Object-Orientation Abusers

SmellDescriptionPrimary Refactoring
Switch StatementsRepeated switch/if-else on type codesReplace Conditional with Polymorphism, Replace Type Code with Subclasses
Temporary FieldField only set in certain circumstancesExtract Class, Introduce Null Object
Refused BequestSubclass doesn't use inherited membersReplace Inheritance with Delegation, Push Down Method/Field
Alternative Classes with Different InterfacesClasses doing similar things with different namesRename Method, Move Method, Extract Superclass

Change Preventers

SmellDescriptionPrimary Refactoring
Divergent ChangeOne class changed for different reasonsExtract Class
Shotgun SurgeryOne change requires many small changes across classesMove Method, Move Field, Inline Class
Parallel Inheritance HierarchiesAdding a subclass to one hierarchy forces adding to anotherMove Method, Move Field

Dispensables

SmellDescriptionPrimary Refactoring
CommentsComments explaining what code does (not why)Extract Method, Rename Variable, Introduce Assertion
Duplicate CodeSame code structure in multiple placesExtract Method, Pull Up Method, Form Template Method
Lazy ClassClass doing too little to justify existenceInline Class, Collapse Hierarchy
Data ClassClass with only fields and getters/settersMove Method, Encapsulate Field, Encapsulate Collection
Dead CodeUnused code, imports, commented-out blocksDelete it (git history has it)
Speculative GeneralityCode built for "someday" that never cameInline Class, Collapse Hierarchy, Remove Parameter

Couplers

SmellDescriptionPrimary Refactoring
Feature EnvyMethod uses another class's data more than its ownMove Method, Extract Method + Move Method
Inappropriate IntimacyClasses know too much about each other's internalsMove Method, Move Field, Replace Delegation with Hidden Delegate
Message Chainsa.getB().getC().getD().doSomething()Hide Delegate, Extract Method
Middle ManClass delegates everything to another classRemove Middle Man, Inline Method
Incomplete Library ClassLibrary missing methods you needIntroduce Foreign Method, Introduce Local Extension

---

Refactoring Techniques Catalog

Organized by category, from Fowler's catalog. Each technique includes its mechanical steps.

Composing Methods

Extract Method

Turn a code fragment into a method whose name explains its purpose.

Mechanics: 1. Create a new method named after what the fragment does (not how) 2. Copy the extracted code into the new method 3. Identify local variables: read-only become parameters, modified become return values 4. Pass parameters and handle return values 5. Replace the original fragment with a call to the new method 6. Test

Before:

void printOwing() {
    printBanner();
    // Print details
    System.out.println("name: " + _name);
    System.out.println("amount: " + getOutstanding());
}

After:

void printOwing() {
    printBanner();
    printDetails(getOutstanding());
}

void printDetails(double outstanding) {
    System.out.println("name: " + _name);
    System.out.println("amount: " + outstanding);
}
Inline Method

Replace a method call with its body when the method body is as clear as the name.

Mechanics: 1. Check the method is not polymorphic (no subclasses override it) 2. Find all callers 3. Replace each call with the method body 4. Delete the method definition 5. Test

Extract Variable

Put the result of an expression (or part of it) in a self-explanatory variable.

Before:

if (platform.toUpperCase().indexOf("MAC") > -1 &&
    browser.toUpperCase().indexOf("IE") > -1 &&
    wasInitialized() && resize > 0) {
    // ...
}

After:

final boolean isMacOs = platform.toUpperCase().indexOf("MAC") > -1;
final boolean isIEBrowser = browser.toUpperCase().indexOf("IE") > -1;
final boolean wasResized = resize > 0;
if (isMacOs && isIEBrowser && wasInitialized() && wasResized) {
    // ...
}
Inline Temp

Replace a temp variable with its expression when the temp is only used once and the expression is clear.

Replace Temp with Query

Extract the expression into a method. Temps that are computed once and reused are replaced with method calls.

Split Temporary Variable

A temp assigned more than once (not loop/collecting) should be split into separate variables, one per responsibility.

Remove Assignments to Parameters

Don't assign to parameters. Use a local variable instead.

Replace Method with Method Object

When a long method uses many local variables that make Extract Method hard, turn the method into its own class, with locals as fields.

Substitute Algorithm

Replace an algorithm with a clearer one.

---

Moving Features Between Objects

Move Method

Move a method to the class where it's used most.

Mechanics: 1. Check all features used by the method on its current class 2. Check for polymorphism (subclass/superclass methods) 3. Create the method on the target class, adapting as needed 4. Reference the target object from the source 5. Turn the source method into a delegating method, or remove it 6. Test

Move Field

Move a field to the class where it's used most.

Extract Class

When a class does the work of two, split it. Create a new class and move relevant fields and methods.

Inline Class

When a class does almost nothing, absorb it into the class that uses it most.

Hide Delegate

Create methods on the server to hide the delegate chain. manager = person.getDepartment().getManager()manager = person.getManager().

Remove Middle Man

When a class is doing too much delegation, call the delegate directly.

Introduce Foreign Method

When a server class needs an additional method but you can't modify it, create a method on the client with the server instance as the first argument.

Introduce Local Extension

When you need multiple foreign methods, create an extension class (subclass or wrapper).

---

Organizing Data

Self Encapsulate Field

Access fields through getters and setters, even within the owning class.

Replace Data Value with Object

When a data item needs additional data or behavior, turn it into an object.

Before:

class Order {
    private String customer;  // Just a string
}

After:

class Order {
    private Customer customer;  // Rich object with name, address, credit rating
}
Change Value to Reference

When you need to share one instance of an object across multiple places.

Change Reference to Value

When a reference object is small, immutable, and you want value semantics.

Replace Array with Object

When an array holds heterogeneous data (String[] row = new String[3] — name, score, wins), replace with an object.

Duplicate Observed Data

Domain data lives in a GUI control but domain logic needs it. Copy the data into a domain object and set up an observer to keep the two in sync (Observer pattern). Separates presentation from domain so each can evolve independently.

Change Unidirectional Association to Bidirectional

Two classes need each other's features but only one holds a reference. Add a back-pointer and make the modifiers on both ends keep the link consistent. Add the reference only when genuinely needed — bidirectional links raise coupling and risk inconsistency.

Change Bidirectional Association to Unidirectional

A two-way link exists but one side no longer uses the other. Drop the unneeded direction. Reduces coupling, simplifies lifecycle management, and avoids "zombie" objects kept alive only by a stale back-pointer.

Replace Magic Number with Symbolic Constant

Replace literal numbers/strings with named constants.

Encapsulate Field

Make public fields private and provide accessors.

Encapsulate Collection

Never return the raw collection. Return a read-only view and provide add/remove methods.

Replace Type Code with Class

Replace a numeric/string type code with a class that has meaningful behavior.

Replace Type Code with Subclasses

When type code affects behavior, use polymorphism instead of conditionals.

Replace Type Code with State/Strategy

Similar to subclasses but uses composition when the type can change at runtime.

Replace Subclass with Fields

When subclasses vary only in constant data, replace them with fields on a single class.

---

Simplifying Conditional Expressions

Decompose Conditional

Extract the condition, then-part, and else-part into separate methods.

Before:

if (date.before(SUMMER_START) || date.after(SUMMER_END)) {
    charge = quantity * _winterRate + _winterServiceCharge;
} else {
    charge = quantity * _summerRate;
}

After:

if (isSummer(date)) {
    charge = summerCharge(quantity);
} else {
    charge = winterCharge(quantity);
}
Consolidate Conditional Expression

Combine multiple conditionals that have the same result.

Consolidate Duplicate Conditional Fragments

Move code that appears in every branch outside the conditional.

Remove Control Flag

Replace control flags with break, continue, or return.

Replace Nested Conditional with Guard Clauses

Use early returns for special cases instead of deep nesting.

Before (arrow code):

double getPayAmount() {
    double result;
    if (_isDead) {
        result = deadAmount();
    } else {
        if (_isSeparated) {
            result = separatedAmount();
        } else {
            if (_isRetired) {
                result = retiredAmount();
            } else {
                result = normalPayAmount();
            }
        }
    }
    return result;
}

After:

double getPayAmount() {
    if (_isDead) return deadAmount();
    if (_isSeparated) return separatedAmount();
    if (_isRetired) return retiredAmount();
    return normalPayAmount();
}
Replace Conditional with Polymorphism

When a conditional chooses different behavior based on the type of an object, use subclasses.

Introduce Null Object

Replace null checks with a null object that provides default behavior.

Introduce Assertion

State assumptions explicitly with assertions.

---

Making Method Calls Simpler

Rename Method

The name should say what the method does. If you can't think of a good name, the method may have multiple responsibilities.

Add Parameter / Remove Parameter

Add parameters when a method needs more info. Remove parameters when the method can get the info another way.

Separate Query from Modifier

A method should either return a value OR change state, never both.

Parameterize Method

Several methods doing similar things with different values → one method with a parameter.

Replace Parameter with Explicit Methods

The inverse: when a parameter essentially selects different behavior, create separate methods.

Preserve Whole Object

Pass the whole object instead of pulling individual fields from it.

Replace Parameter with Method

(refactoring.guru: Replace Parameter with Method Call) When a parameter can be computed from data the object already has, remove the parameter and let the method call the query itself.

Introduce Parameter Object

Group parameters that naturally go together into an object.

Remove Setting Method

Make a field immutable by removing its setter and setting it in the constructor.

Hide Method

Make methods private when they're not used outside the class.

Replace Constructor with Factory Method

When you need more flexibility than a simple constructor call.

Replace Error Code with Exception

Throw an exception instead of returning an error code.

Replace Exception with Test

Check the condition first instead of catching an exception.

---

Dealing with Generalization

Pull Up Field/Method/Constructor Body

Move identical fields/methods/constructor code from subclasses to superclass.

Push Down Method/Field

Move behavior from superclass to only the subclasses that use it.

Extract Subclass

Create a subclass for a subset of features used in some instances.

Extract Superclass

Create a superclass for shared features of similar classes.

Extract Interface

Create an interface from a subset of a class's public methods.

Collapse Hierarchy

Merge a superclass and subclass when they're not different enough.

Form Template Method

Generalize an algorithm in the superclass, letting subclasses fill in the specifics.

Replace Inheritance with Delegation

When a subclass only uses part of the superclass, use composition instead.

Replace Delegation with Inheritance

When a delegating class needs access to all of the delegate's behavior.

---

The Refactoring Process

Phase 1: Prepare

1. Write characterization tests if they don't exist. These capture current behavior — they don't need to be elegant, just comprehensive enough to catch regressions. 2. Commit current state. Start from a clean working tree. 3. Create a branch for the refactoring. Keep it separate from feature work.

Phase 2: Identify

1. Smell the code. Use the smell catalog above to classify what's wrong. 2. Understand the code. Read it thoroughly. You must understand what it does before changing it. 3. Choose the right refactoring. Pick from the technique catalog. Know what the result looks like before you start.

Phase 3: Refactor (Small Steps)

For each step: 1. Make one small change. One refactoring technique at a time. 2. Compile. The code should compile after every change. 3. Run tests. All tests must pass. If they don't, you've changed behavior. 4. Commit. Create a commit with a message like refactor: extract validateEmail method.

Repeat until the smell is resolved.

Phase 4: Verify

1. All tests pass. Non-negotiable. 2. Manual check. Briefly run the application or review the diff for unintended changes. 3. Performance. Ensure no performance regression. Simple refactorings rarely cause them, but check.

Phase 5: Clean Up

1. Remove stale comments. If a refactoring made a comment obvious, delete the comment. 2. Check for dead code. After refactorings, unused code may emerge. 3. Final commit. Summarize the refactoring sequence.

---

Refactoring Checklist

Code Quality

  • [ ] Functions are small (< 20 lines preferred, < 50 lines max)
  • [ ] Each function does one thing (single responsibility)
  • [ ] No duplicated code (DRY)
  • [ ] Names describe what, not how
  • [ ] No magic numbers or strings
  • [ ] Dead code removed

Structure

  • [ ] Related code is grouped together
  • [ ] Module boundaries are clear
  • [ ] Dependencies flow in one direction (no cycles)
  • [ ] No circular dependencies

Conditionals

  • [ ] Guard clauses replace deep nesting
  • [ ] Complex conditions extracted to named methods
  • [ ] Polymorphism replaces type-switching conditionals
  • [ ] Null Object pattern where appropriate

Type Safety (typed languages)

  • [ ] Types defined for all public APIs
  • [ ] No any usage without qualification
  • [ ] Nullable types explicitly marked
  • [ ] Type codes replaced with classes/enums

Testing

  • [ ] Refactored code is tested
  • [ ] Edge cases are covered
  • [ ] All tests pass after each step
  • [ ] Characterization tests capture pre-refactoring behavior

---

Language-Specific Guidance

Java

  • Prefer final for locals that shouldn't change
  • Use IDE automated refactorings (Eclipse/IntelliJ) for mechanical steps
  • Leverage the type system: enums, records (Java 14+), sealed classes (Java 17+)

JavaScript/TypeScript

  • Use destructuring to reduce parameter count
  • Prefer const over let for immutable bindings
  • Use TypeScript union types instead of type codes
  • Nullish coalescing (??) and optional chaining (?.) eliminate null-check noise

Python

  • Use type hints for documenting intent during refactoring
  • Use dataclasses to replace tuple/data-class patterns
  • Use @property to replace getters
  • Context managers for resource cleanup patterns

Go

  • Small interfaces preferred: accept interfaces, return structs
  • Use named return values when they improve clarity
  • Table-driven tests pair well with refactoring
  • Avoid deep nesting with early returns

Rust

  • Use Result and Option instead of error codes and null
  • Pattern matching replaces if-else chains
  • From trait implementations clean up type conversions
  • Derive macros reduce boilerplate

---

Common Refactoring Sequences

Extract Method Sequence

1. Create a new method named after intent 2. Copy code fragment into new method 3. Identify local variables → parameters / return values 4. Call new method from original location 5. Test

Replace Conditional with Polymorphism Sequence

1. Create subclasses for each variant 2. Create a factory method that returns the right subclass 3. Move the conditional body to the appropriate subclass method 4. Delete the conditional

Extract Class Sequence

1. Identify a coherent subset of fields and methods 2. Create a new class 3. Create an instance from the old class 4. Move fields and methods one at a time 5. Update references in old class 6. Test after each move

Inline Class Sequence

1. Identify all callers of the target class 2. Move all methods/fields to the absorbing class 3. Redirect all references to the absorbing class 4. Delete the empty class 5. Test

---

Safety Protocol

Before You Touch Anything

1. Characterization tests  →  capture what the code does now
2. Git commit              →  save a known-good state
3. Branch                  →  isolate refactoring from other work

Every Single Step

1. One change              →  one refactoring technique
2. Compile                 →  must compile clean
3. Tests                   →  every test must pass
4. Commit                  →  message: "refactor: <technique> <what>"

If Tests Break

1. Undo the last change
2. Understand what broke and why
3. Try a smaller step
4. If the test was wrong and behavior was correct, fix the test FIRST, then retry

On Completion

1. Full test suite         →  all tests pass
2. Manual smoke test       →  quick sanity check
3. Self-review diff        →  catch unintended changes
4. Final commit            →  describe the overall transformation

---

Design Patterns in Refactoring

Strategy Pattern

Replace a conditional that chooses an algorithm. Smell: Switch on type code with different behavior per branch. Technique: Replace Conditional with Polymorphism + Extract Method.

Template Method

Extract common algorithm skeleton to superclass, letting subclasses fill in the variants. Smell: Duplicate code with slight variations. Technique: Form Template Method.

State Pattern

Replace a state-based conditional by extracting each state's behavior into a class. Smell: Switch on status field with behavior variation. Technique: Replace Type Code with State/Strategy.

Composite Pattern

Treat individual objects and groups uniformly. Smell: Client code has special handling for single vs. collection cases. Technique: Extract Interface + Create Composite.

Decorator Pattern

Add behavior dynamically by wrapping objects. Smell: Conditional logic for optional behaviors. Technique: Extract Class + use composition.

Null Object Pattern

Replace null checks with a default object. Smell: Repeated if (x == null) checks. Technique: Introduce Null Object.

---

Edge Cases & Gotchas

ScenarioHandling
No tests existWrite characterization tests first. Run the code with various inputs, capture outputs. These are your safety net.
Refactoring breaks a distant testFIRST understand why. Maybe the test relied on implementation detail. If so, fix the test to test behavior, not implementation. Then resume.
User wants behavior change + refactor togetherREFUSE. Do them separately. Refactor first to make the behavior change easy, commit, then change behavior.
Method is too complex to step throughUse Replace Method with Method Object. Turn the whole method into a class where each step can be extracted.
Refactoring across a large codebaseExtract a micro-service or module boundary first. Then refactor within the boundary. "There is a refactoring for everything except too many refactorings."
IDE automated refactoring availableUse it. Modern IDEs can safely rename, extract method, introduce variable, etc. Only do it manually when the IDE can't.
Undo neededgit stash or git reset --hard back to last commit. Small commits make this painless.

---

Resources

Related skills

This week in AI coding

Five minutes, every Monday - the tools, releases and tactics for developers.

unsubscribe anytime.