# What Is Refactoring

> Refactoring changes the internal structure of code in small, behavior-preserving steps so it becomes cheaper to read and change.

- kind: guide
- category: refactoring
- aliases: Refactoring basics
- canonical: https://aipatterns.dev/guides/what-is-refactoring
- inspired-by: https://refactoring.guru/refactoring/what-is-refactoring

## Definition

Refactoring is a change to the structure of code that leaves its observable behavior unchanged. Inputs that produced a result before still produce the same result after. The only thing that moves is how the code is arranged: names, boundaries, where data lives, how responsibilities split.

**If a change alters what the program does, it is not a refactoring, no matter how small it is.** Fixing a bug, adding a field to an API response or changing an error message are behavior changes. They can happen next to a refactoring, but never inside the same step.

The word covers two things:

- **A refactoring** (noun): one named, mechanical transformation such as [Extract Method](https://aipatterns.dev/refactoring/techniques/extract-method.md) or [Replace Temp with Query](https://aipatterns.dev/refactoring/techniques/replace-temp-with-query.md).
- **Refactoring** (activity): a sequence of those transformations applied toward a goal, such as "make the pricing rules testable".

## What counts as clean code

Refactoring aims at code that is cheap to change. That usually means:

- **Names say what things do.** A reader can guess a function's behavior from its signature.
- **Each unit has one reason to change.** Pricing rules and email formatting do not share a class.
- **No duplication of knowledge.** One rule lives in one place, so a fix lands once.
- **Small surface area.** Functions take few arguments, classes expose few public members.
- **Tests pass and are fast.** Clean code that cannot be verified is a guess.
- **No surprises.** Queries do not modify state; a method named `get` does not write to the database.

Clean code is not short code. A three-line function full of clever chaining can be harder to change than ten plain lines.

## What refactoring is not

- **Not a rewrite.** A rewrite replaces code wholesale and has to rediscover every edge case. Refactoring keeps the program working at every step.
- **Not optimization.** Performance work often makes code harder to read. It is a separate goal with separate verification (benchmarks as well as tests).
- **Not adding features.** Kent Beck's "two hats" rule applies: at any moment you are either adding behavior or restructuring, never both.
- **Not reformatting.** Running a formatter is harmless, but it does not change structure. Keep formatter churn in its own commit so it does not hide real changes in a diff.

## Why it matters for agents

An AI agent reads code it did not write, in a context window that is always too small. Structure decides how much an agent must load to make a correct change:

- A 400-line method forces the agent to hold the whole thing in context. Five named 80-line methods let it load one.
- Duplicated logic means the agent patches one copy and misses the other three. See [Duplicate Code](https://aipatterns.dev/refactoring/smells/duplicate-code.md) and [Shotgun Surgery](https://aipatterns.dev/refactoring/smells/shotgun-surgery.md).
- Primitive values with implicit meaning (`status: 3`) lead to plausible but wrong code. See [Primitive Obsession](https://aipatterns.dev/refactoring/smells/primitive-obsession.md).

Refactoring before a feature change often makes the feature change smaller and safer. That is the main reason to do it.

## The vocabulary

This reference organizes refactoring into three layers:

| Layer | What it is | Where |
|---|---|---|
| Smells | Symptoms that suggest the structure is hurting you | [Bloaters](https://aipatterns.dev/refactoring/smells/bloaters.md), [OO abusers](https://aipatterns.dev/refactoring/smells/oo-abusers.md), [Change preventers](https://aipatterns.dev/refactoring/smells/change-preventers.md), [Dispensables](https://aipatterns.dev/refactoring/smells/dispensables.md), [Couplers](https://aipatterns.dev/refactoring/smells/couplers.md) |
| Techniques | Named, safe transformations that remove a smell | [Composing methods](https://aipatterns.dev/refactoring/techniques/composing-methods.md), [Moving features](https://aipatterns.dev/refactoring/techniques/moving-features-between-objects.md), [Organizing data](https://aipatterns.dev/refactoring/techniques/organizing-data.md), [Simplifying conditionals](https://aipatterns.dev/refactoring/techniques/simplifying-conditional-expressions.md), [Simplifying method calls](https://aipatterns.dev/refactoring/techniques/simplifying-method-calls.md), [Generalization](https://aipatterns.dev/refactoring/techniques/dealing-with-generalization.md) |
| Patterns | Target designs you may refactor toward when a structure keeps recurring | [Design patterns](https://aipatterns.dev/guides/what-is-a-pattern.md) |

A smell page names the techniques that treat it. A technique page names the smells it fixes. Follow those links rather than guessing.

## A small example

```ts
// Before: one function computes, formats and decides.
function invoiceLine(item: { qty: number; unitCents: number; taxable: boolean }) {
  const base = item.qty * item.unitCents;
  const tax = item.taxable ? Math.round(base * 0.2) : 0;
  return `${item.qty} x ${(item.unitCents / 100).toFixed(2)} = ${((base + tax) / 100).toFixed(2)}`;
}

// After: same output, three named pieces.
const VAT_RATE = 0.2;
const lineTotal = (i: { qty: number; unitCents: number; taxable: boolean }) =>
  i.qty * i.unitCents + (i.taxable ? Math.round(i.qty * i.unitCents * VAT_RATE) : 0);
const money = (cents: number) => (cents / 100).toFixed(2);

function invoiceLineRefactored(i: { qty: number; unitCents: number; taxable: boolean }) {
  return `${i.qty} x ${money(i.unitCents)} = ${money(lineTotal(i))}`;
}
```

The steps were [Replace Magic Number with Symbolic Constant](https://aipatterns.dev/refactoring/techniques/replace-magic-number-with-symbolic-constant.md), then [Extract Method](https://aipatterns.dev/refactoring/techniques/extract-method.md) twice. A test that compares both versions on a handful of inputs confirms nothing changed.

## Next

- Read [Technical debt](https://aipatterns.dev/guides/technical-debt.md) for why code drifts toward a mess.
- Read [When to refactor](https://aipatterns.dev/guides/when-to-refactor.md) to decide whether now is the moment.
- Read [How to refactor](https://aipatterns.dev/guides/how-to-refactor.md) for the step-by-step discipline.
