Skip to content

Extract Function

Take a coherent fragment of code, move it into a new function, and name that function after the purpose it serves. The original site now calls the helper, so it reads as a short list of named steps instead of a wall of detail.

This is the cure for the Long Function — and for any block of code that needs a comment to explain what it does. A comment that says “now calculate the tax” above ten lines is a flashing sign that those ten lines want to be a function called taxFor. When the function name carries the intent, the comment becomes unnecessary and the caller becomes readable.

A receipt function that computes a subtotal, applies tax, then prints. Before, it does everything inline. After, each job is a named helper.

// Before
function printReceipt(items: { price: number; qty: number }[]): void {
let subtotal = 0;
for (const item of items) {
subtotal += item.price * item.qty;
}
const tax = subtotal * 0.07;
console.log(`Subtotal: ${subtotal.toFixed(2)}`);
console.log(`Tax: ${tax.toFixed(2)}`);
console.log(`Total: ${(subtotal + tax).toFixed(2)}`);
}
// After
function printReceipt(items: { price: number; qty: number }[]): void {
const sub = subtotal(items);
const tax = taxFor(sub);
printLines(sub, tax);
}
function subtotal(items: { price: number; qty: number }[]): number {
return items.reduce((sum, item) => sum + item.price * item.qty, 0);
}
function taxFor(amount: number): number {
return amount * 0.07;
}
function printLines(sub: number, tax: number): void {
console.log(`Subtotal: ${sub.toFixed(2)}`);
console.log(`Tax: ${tax.toFixed(2)}`);
console.log(`Total: ${(sub + tax).toFixed(2)}`);
}
flowchart LR
  subgraph Before["Before"]
    A["printReceipt()<br/>— compute subtotal<br/>— compute tax<br/>— print lines"]
  end
  subgraph After["After"]
    B["printReceipt()<br/>calls helpers"]
    B --> C["subtotal()"]
    B --> D["taxFor()"]
    B --> E["printLines()"]
  end
  Before -.->|"Extract Function"| After
One long function becomes a caller plus three named helpers
  1. Decide on the fragment to extract and a name that says what it accomplishes, not how. If you cannot name it cleanly, the fragment may not be a coherent unit yet — adjust your boundaries.
  2. Create a new empty function with that name.
  3. Copy the fragment into the new function.
  4. Look at the variables the fragment reads: pass them in as parameters. Look at the variables it produces and the outside code still needs: return them.
  5. Replace the original fragment with a call to the new function.
  6. Run your tests. Behaviour must be unchanged.
  7. Repeat for the next fragment. Keep each extraction small so a failing test points at one tiny change.

Reach for Extract Function whenever a block has a clear single purpose, whenever you are tempted to write a clarifying comment, or whenever you spot the same fragment duplicated in two places — extracting once lets both sites call the shared helper.

The cost is a small jump in navigation: the reader follows a name to its definition. That trade is almost always worth it, because a good name lets most readers stop without following the jump. The inverse refactoring is Inline Function: if a helper’s name says no more than its body, fold it back.

When picking a name for the extracted function, what should it describe?
How do you handle a variable the extracted fragment reads but does not own?
Which smell is Extract Function the primary cure for?
What is the inverse of Extract Function?