Sign inGet started
Skills / Software-engineering

Refactoring

Any fool can write code that a computer can understand. Good programmers write code that humans can understand.

Martin Fowler's Refactoring methodology gives software engineers a systematic, named vocabulary for improving the internal design of existing code without changing its observable behavior. Built around a diagnostic layer of Code Smells and a prescriptive catalog of 60+ named operations — each with step-by-step Mechanics — it turns messy, intuition-driven cleanup into a repeatable engineering practice. It's for any developer who knows their code needs work but can't quite articulate what's wrong or how to fix it safely.

By Martin Fowler · Free
Specimen 01 · Live diagnosisRefactoring
Input

“Tests are passing. Here's the function: ```js function statement(invoice, plays) { let totalAmount = 0; let volumeCredits = 0; let result =…”

Diagnosis
Paste in the code you want to work on — a function, a class, or a module — and tell me what it's supposed to do.
Full transcript ↓
Calibrated referenceagent-skills.ai
The gap

Make the change easy — then make the easy change

Fowler's Refactoring methodology operates in two interlocking layers. The first is diagnostic: Code Smells — named anti-patterns grouped into five families (Bloaters, OO Abusers, Change Preventers, Dispensables, and Couplers) — give engineers objective signals that something is wrong and precisely where. The second is prescriptive: a catalog of 60+ named refactoring operations, each documented with a Motivation, step-by-step Mechanics, and before/after code examples. The process follows a strict workflow — identify the smell, select the catalog refactoring, verify a passing test safety net, apply the mechanics in small incremental steps, re-run tests — repeated until the design is clean. Fowler's 'Two Hats' rule enforces that you are either adding functionality or refactoring (changing internal structure without changing observable behavior) — never both simultaneously.

The problem

Developers know their code is getting harder to change — but without a shared vocabulary, 'this is messy' stays a vague feeling, not an actionable diagnosis. Teams pile new features onto code that was never restructured, accumulating technical debt that compounds every sprint. The real problem isn't that engineers don't care about code quality; it's that they lack a systematic framework to identify exactly what's wrong, name it precisely, and apply a safe, proven cure.

The solution

You'll stop saying 'this code is a mess' and start saying 'this is a Long Method with Feature Envy — let's Extract Function and Move Function to fix it.' Every refactoring session ends with cleaner, more intention-revealing code and a test suite still green at every step.

You bring
  • A code snippet, function, class, or module you want to improve
  • Context about what the code is supposed to do (its observable behavior to preserve)
  • Information about your test coverage — whether tests exist and if they're currently passing
  • Your constraints: language, time pressure, risk tolerance, or team norms around changesets
You get
  • A named Code Smell diagnosis using Fowler's taxonomy — 'Long Method with Feature Envy' not just 'messy code'
  • A recommended catalog refactoring with Motivation explaining why it addresses the smell
  • Before/after code produced by walking through the numbered Mechanics, with behavior preserved at every step
  • A prioritized Refactoring Plan for larger code sections, sequenced so each step keeps the test suite green
In action

Watch the methodology work.

Three specimens from a single real session: the same situation, unaided and calibrated, the full transcript, and the skill answering live in the channel where the work happens.

Fig.01The same situation, two ways
Specimens A · B
Specimen AVague
Unaided

“A 60-line `statement()` function handles play pricing, volume credit calculation, and report formatting in a single tangled loop — with a switch statement on play type that the team is afraid to touch. Every time a new genre is requested, someone has to open this function, understand all of it, and hope they don't break billing. The team has started routing around it instead of into it.”

×Vague — nothing concrete to act on.
Specimen BCalibrated
With Refactoring

“The same function is now a clean coordinator: `amountFor()`, `volumeCreditsFor()`, and `totalVolumeCredits()` are named, independently testable functions. Play-type pricing lives in `TragedyCalculator` and `ComedyCalculator` subclasses — adding a new genre means adding a new class, not editing a switch. Three engineers can work on billing in the same sprint without merge conflicts.”

Specific, grounded, and ends with one clear next step.
Fig.02A real session, unedited
In-app · assistant
RefactoringClaude
Refactoring
Paste in the code you want to work on — a function, a class, or a module — and tell me what it's supposed to do. I'll run it through Fowler's Code Smell taxonomy to diagnose exactly what's wrong, then we'll select the right refactoring from the catalog and walk through the Mechanics step by step. One question before we start: do you have tests passing right now?
Tests are passing. Here's the function: ```js function statement(invoice, plays) { let totalAmount = 0; let volumeCredits = 0; let result = `Statement for ${invoice.customer}\n`; const format = new Intl.NumberFormat('en-US', { style: 'currency', currency: 'USD', minimumFractionDigits: 2 }).format; for (let perf of invoice.performances) { const play = plays[perf.playID]; let thisAmount = 0; switch (play.type) { case 'tragedy': thisAmount = 40000; if (perf.audience > 30) thisAmount += 1000 * (perf.audience - 30); break; case 'comedy': thisAmount = 30000; if (perf.audience > 20) thisAmount += 10000 + 500 * (perf.audience - 20); thisAmount += 300 * perf.audience; break; default: throw new Error(`unknown type: ${play.type}`); } volumeCredits += Math.max(perf.audience - 30, 0); if ('comedy' === play.type) volumeCredits += Math.floor(perf.audience / 5); result += ` ${play.name}: ${format(thisAmount/100)} (${perf.audience} seats)\n`; totalAmount += thisAmount; } result += `Amount owed is ${format(totalAmount/100)}\n`; result += `You earned ${volumeCredits} credits\n`; return result; } ``` What's wrong with it?
Good — passing tests mean we have our safety net. Now the diagnosis.
Code Smells identified:
1.
Long Method (Bloater) — this single function handles pricing logic, volume credit calculation, and string formatting. Three distinct responsibilities, three reasons to change.2. Switch Statement (OO Abuser) — `switch (play.type)` will need to be opened and modified every time a new play genre is added. This is a Divergent Change smell waiting to compound.3. Replace Temp with Query opportunity — `thisAmount`, `totalAmount`, and `volumeCredits` accumulate in the loop but could be extracted into intention-revealing functions instead of temporary variables.
Recommended refactoring sequence (Preparatory Refactoring first):1. Extract Function — pull `amountFor(perf, play)` out of the loop body2. Extract Function — pull `volumeCreditsFor(perf, play)` out3. Replace Temp with Query — replace the accumulator temps with function calls4. Replace Conditional with Polymorphism — eliminate the switch via a `PerformanceCalculator` class hierarchy
The first three clear the ground for the fourth. Want to start with Extract Function on the pricing logic?
Yes — walk me through the Extract Function Mechanics.
Extract Function — Mechanics (Fowler catalog):
Step 1: Create a new function named for its intent, not its implementation. We'll call it `amountFor(aPerformance, play)` — the name states what it computes.
Step 2: Copy the pricing fragment into the new function.
Step 3: Identify variables used only inside the fragment. `thisAmount` becomes the return value; `perf` and `play` become parameters. I'm also applying Rename Variable here: `perf` → `aPerformance` inside the function to improve readability.
Step 4: Replace the original fragment with a call to the new function.
```jsfunction amountFor(aPerformance, play) { let result = 0; switch (play.type) { case 'tragedy': result = 40000; if (aPerformance.audience > 30) result += 1000 * (aPerformance.audience - 30); break; case 'comedy': result = 30000; if (aPerformance.audience > 20) result += 10000 + 500 * (aPerformance.audience - 20); result += 300 * aPerformance.audience; break; default: throw new Error(`unknown type: ${play.type}`); } return result;}```
In `statement`, the loop now reads: `let thisAmount = amountFor(perf, play);`
Run your tests now. If they're green, we've preserved behavior while giving the pricing logic a name and a home. Ready for step 2 — extracting `volumeCreditsFor`?
Tests are green! The Switch Statement smell you flagged — is that what Replace Conditional with Polymorphism fixes later?
Exactly. The Switch Statement smell signals type-based dispatch that belongs in the type itself. Replace Conditional with Polymorphism is the catalog operation: you create a `PerformanceCalculator` base class, then `TragedyCalculator` and `ComedyCalculator` subclasses — each overriding an `amount()` method with their own logic. The switch disappears entirely.
Fowler's Motivation for this refactoring: a switch statement that must be updated every time a type is added violates the Open/Closed Principle. Replacing it with polymorphism means adding a new play genre = adding a new subclass, touching no existing code.
But that's a Hat change — structural enough to be its own commit. Right now we're wearing the Refactoring Hat and we're not done: `statement` still accumulates totals inline. Let's finish the Extract Function passes and the Replace Temp with Query step first, get `statement` down to a clean coordinator, then sequence the polymorphism move with full tests green throughout.
Reply to Refactoring
What the skill is doing
01Code Smell Diagnosis
02Catalog Refactoring Selection
03Mechanics Walkthrough
Fig.03The same skill, in the channel you already use
WhatsApp · live
9:41
RRefactoringtyping…
Messages are end-to-end encrypted. No one outside of this chat can read them.
Today
Tests are passing. Here's the function: ```js function statement(invoice, plays) { let totalAmount = 0; let volumeCredits = 0; let result = `Statement…9:14✓✓
Paste in the code you want to work on — a function, a class, or a module — and tell me what it's supposed to do.9:14
One question before we start: do you have tests passing right now?9:15
Message

The same skill, where the work happens.

No new app to learn. The methodology runs over the WhatsApp Business API, so the answer lands as a reply in the thread you’re already in — same rigour, zero context-switch.

Reads the situation, names the pattern, returns one concrete next move.
Delivered in seconds, inside a conversation that already exists.
Specimen · WhatsApp Business API · live
Capabilities

What it does, specifically.

Each capability is a distinct move drawn straight from the source methodology — not a generic assistant guessing.

CapabilityC-01

Code Smell Diagnosis

Analyze a code snippet and identify which of Fowler's named Code Smells are present — Long Method, Large Class, Primitive Obsession, Feature Envy, Divergent Change, Shotgun Surgery, and 20+ others. Each diagnosis classifies the smell by family, explains why it's problematic, and identifies which catalog refactoring(s) apply.

Based on Fowler's taxonomy of five smell families (Bloaters, OO Abusers, Change Preventers, Dispensables, Couplers) from Chapter 3 of Refactoring, 2nd ed., providing objective diagnostic criteria rather than subjective style preferences.
CapabilityC-02

Catalog Refactoring Selection

Given identified smells, recommend the specific named catalog operation(s) to apply — Extract Function, Replace Conditional with Polymorphism, Introduce Parameter Object, Move Function, Replace Temp with Query, and 55+ others — with the Motivation explaining why this refactoring addresses this smell.

Draws from Fowler's 60+ named refactoring catalog, each entry documented with Motivation, Mechanics (numbered steps), and before/after examples; the catalog is published at martinfowler.com/refactoring.
CapabilityC-03

Mechanics Walkthrough

Step through the numbered Mechanics for a chosen refactoring, producing before/after code, narrating each step, and flagging test checkpoints. The walkthrough preserves the observable behavior of the code while restructuring its internal design.

Applies Fowler's fixed catalog documentation template — Motivation, Mechanics (numbered steps), Example — which structures every refactoring entry and guarantees reproducible, safe application.
CapabilityC-04

Refactoring Sequence Planning

For a larger function, class, or module, produce a prioritized sequence of refactorings in the order they should be applied — starting with structural changes that make subsequent refactorings easier (Preparatory Refactoring) and scheduling test verification checkpoints throughout.

Implements Fowler's Preparatory Refactoring principle: 'make the change easy, then make the easy change' — sequencing lower-risk, structural refactorings first to unlock higher-impact operations without destabilizing the codebase.
CapabilityC-05

Two Hats Coaching

Coach engineers on when to switch between the Refactoring Hat and the Feature Hat — recognizing mid-task scope creep, deciding when the structure resists a change enough to warrant a refactoring pass first, and committing clean refactoring-only changesets that don't mix structural improvements with new behavior.

Based on Fowler's 'Two Hats' metaphor from Refactoring: you wear either the refactoring hat (structure changes, behavior preserved) or the feature hat (behavior added, structure unchanged) — switching deliberately, never wearing both at once.
Tested

Graded before it shipped.

Every skill is scored against independent scenarios for methodology fidelity before it goes live — not vibes, a rubric.

What it produces
OutputD-01

Code Smell Report

A structured diagnosis naming each smell present in a code snippet, classified by Fowler's smell family, with severity assessment and the catalog refactoring(s) recommended to address each one.

OutputD-02

Refactoring Plan

A sequenced, step-by-step plan naming each catalog operation to apply, the order to apply them (Preparatory Refactoring first), intermediate test checkpoints, and the expected design improvement at each stage.

OutputD-03

Mechanics Diff

A before/after code transformation produced by walking through a refactoring's numbered Mechanics — annotated with what each step accomplished, which smell it removed, and how observable behavior was preserved throughout.

OutputD-04

Technical Debt Summary

A human-readable translation of Code Smell findings into language suitable for engineering managers or product stakeholders — naming the specific risks, estimated remediation effort, and business impact of each identified smell.

The source

Grounded in the original work.

Every answer traces back to a real source and the practitioner who wrote it — not a secondhand summary. Here is the source of record.

Source authorA-01

Martin Fowler

Martin Fowler is Chief Scientist at ThoughtWorks and one of the most influential voices in software design. His book 'Refactoring: Improving the Design of Existing Code' — first published in 1999 and updated in 2018 with JavaScript examples — gave the entire industry its shared vocabulary for code improvement and is required reading in CS programs worldwide. He is also the author of 'Patterns of Enterprise Application Architecture', 'UML Distilled', and 'Domain-Specific Languages', and maintains an extensive catalog and bliki at martinfowler.com.

Status · Inspired by Martin Fowler’s work — not yet claimed. Are you Martin Fowler?
Primary sourceS-01

Refactoring: Improving the Design of Existing Code (2nd ed., 2018)

by Martin Fowler

Chief Scientist at ThoughtWorks; author of Refactoring (1999/2018), Patterns of Enterprise Application Architecture, and six other seminal software engineering books.

Read the original ↗
Citationmartinfowler.com
In the build queue

Be first to run it.

Refactoring is being built right now. Leave your email and we’ll tell you the moment it goes live.

Notify meEmail
At launchI have a function that's doing too much — pricing, formatting, and credit calculation all tangled together in one loop. Can we run it through Fowler's smell taxonomy and build a step-by-step refactoring plan to break it apart safely?