Symptom

A function body that needs a mental outline before it can be read — multiple concerns interleaved, or chunks of statements that share a single domain purpose without a name. The reader's rises because every read reconstructs the outline; small edits to one concern require holding all the others in working memory.

Goal

Each function reads as a single named domain step — what it does, not how. The calling code becomes a sequence of named intentions; readers verify the workflow at the top level and drill into helpers only when the named step's body is the point of interest, supporting at the procedural level.

Before the refactoring

function invoiceTotal(invoice) {
let total = 0;
for (const line of invoice.lines) {
total += line.qty * line.unitPrice;
if (line.qty >= 100) total -= line.qty * line.unitPrice * 0.05;
}
total += total * invoice.taxRate;
return Math.round(total * 100) / 100;
}

After the refactoring

function invoiceTotal(invoice) {
const subtotal = subtotalAfterBulkDiscount(invoice);
const withTax = subtotal * (1 + invoice.taxRate);
return roundToCents(withTax);
}
Example source: Illustrative example written for this site; the refactoring itself is catalogued in Martin Fowler's Refactoring (Addison-Wesley, 2018), see the chapter on A First Set of Refactorings.
Pressure

Every reader pays the outline cost on every read; small edits to one concern require holding all the others in working memory, and PRs touch the same function for unrelated reasons. The team's compounds across reviewers who must re-derive the function's structure each time; merge conflicts collect at the same body.

Tradeoff

Over-eager extraction can produce a fan-out of one-line functions; aim for extractions that earn their name with at least one decision or transformation. The team's can rise rather than drop if the extractions don't carry domain meaning, because every helper becomes a name to find, load, and verify on every traversal.

Relief

Calling code becomes a sequence of named intentions; bugs concentrate inside the now-named subroutines because the reader can localize the failure to one named step. The team's drops because adding a new step is one new function rather than a new branch inside an already-cluttered body, and tests target the helper directly.

Trap

Tiny one-line helpers where the workflow can no longer be read linearly — extraction that doesn't earn its name fragments the procedure into pieces too small to mean anything. The fan-out adds to the call graph; readers carry the of jumping between trivial helpers to reconstruct the original procedure.