Skip to main content

Extract Variable, Rename, and Change Function Declaration

What This Concept Is

Three refactor moves that treat naming as a structural concern, not a cosmetic one.

Extract Variable: pull a sub-expression out and give it a name. The name explains why the expression matters.

Rename Variable / Rename Field / Rename Function: change the name of an element everywhere it appears. When the element is published (used by external callers), do it via Change Function Declaration in two phases.

Change Function Declaration: change a function's name, its parameter list, or its return shape. The parallel-change version: add the new form, migrate callers, remove the old form.

Why It Matters Here

Naming is the primary way intent shows up in code. A renamed variable prevents five future hours of someone's confusion. These are the cheapest refactors and the highest-leverage. They are also the ones most often skipped because "it still works."

Change Function Declaration is the move that connects small-step refactoring to large-scale API evolution (see Cluster 5: parallel change).

Concrete Example

Extract Variable:

// Before
return order.quantity * order.itemPrice -
Math.max(0, order.quantity - 500) * order.itemPrice * 0.05 +
Math.min(order.quantity * order.itemPrice * 0.1, 100);

// After
const basePrice = order.quantity * order.itemPrice;
const quantityDiscount = Math.max(0, order.quantity - 500) * order.itemPrice * 0.05;
const shipping = Math.min(basePrice * 0.1, 100);
return basePrice - quantityDiscount + shipping;

Rename (wide-scope variable), using Encapsulate Variable first:

// Step 1: encapsulate
let tpHd = "untitled";
function title() { return tpHd; }
function setTitle(arg) { tpHd = arg; }

// Step 2: rename the storage; callers keep using title()/setTitle()
let _pageTitle = "untitled";
function title() { return _pageTitle; }
function setTitle(arg) { _pageTitle = arg; }

Change Function Declaration (parallel change):

// Existing, external callers
function circum(radius) { return 2 * Math.PI * radius; }

// Phase 1: add new name, keep the old one delegating
function circumference(radius) { return 2 * Math.PI * radius; }
function circum(radius) { return circumference(radius); }

// Phase 2: migrate callers (one commit per batch)

// Phase 3: delete circum()

Common Confusion / Misconception

"Rename is trivial -- just find-and-replace." For a local variable, yes. For a field or function used across a codebase, you are doing a declaration change; treat it as such. Use the IDE's rename refactor, and if the symbol is published, use the two-step delegating version.

Extract Variable vs Extract Function: if the name has meaning only inside this function, use Extract Variable. If the name would be useful to other code in the module, use Extract Function instead (or Replace Temp with Query).

How To Use It

Check Yourself

  1. When is Extract Variable the wrong move and Extract Function the right one?
  2. Why is renaming a public API method not a one-step operation?
  3. A function takes (x, y) that are always called with coord.x, coord.y. Which of the three moves fixes this, and which concept in Cluster 4 follows?

Mini Drill or Application

Find a one-line expression of more than ~40 characters in your code. Apply Extract Variable. Now reread the function aloud. If the new names let someone unfamiliar follow the calculation in one pass, stop. If not, keep extracting or consider Extract Function.

Video and Lecture References

Article References

External Exercises

Depth Path

  • Read This Only If Stuck - Fowler chunks 041 (Extract Variable), 042 (Inline Variable / Change Function Declaration), 043 (Change Function Declaration), 045 (Rename Variable)
  • Optional deep dive: chunk 044 (Encapsulate Variable) for wide-scope rename

Source Backbone

Refactoring is the canonical book backbone for this module. Use these sources after attempting the refactor and tests yourself.