Definition, Safety Net & Core Techniques
The Definition That Matters
Refactoring changes internal structure WITHOUT changing external behavior. A bug fix or a new feature — even one that also reorganizes code — is not, strictly, a refactoring. This distinction is why refactoring is considered comparatively low-risk: the goal is explicitly to preserve behavior.
Tests as the Safety Net
A test suite gives a fast way to verify behavior actually didn't change after each step. When code has NO tests, write "characterization tests" first — tests that lock in current actual behavior, even if imperfectly understood — before refactoring, per Michael Feathers' legacy-code approach.
Small Steps
A sequence of small, individually test-verified steps makes it far easier to pinpoint what broke than one large sweeping change bundling many edits together.
Core Techniques
// Extract Method — pull a fragment into its own well-named function
function printInvoice(order) {
const total = order.items.reduce((sum, i) => sum + i.price, 0);
console.log(`Total: $${total}`);
}
// ->
function calculateTotal(order) {
return order.items.reduce((sum, i) => sum + i.price, 0);
}
function printInvoice(order) {
console.log(`Total: $${calculateTotal(order)}`);
}
// Replace Magic Number with Named Constant
if (status === 3) { ... } // BAD — what is 3?
const STATUS_APPROVED = 3;
if (status === STATUS_APPROVED) { ... } // GOODRename Variable/Method is one of the highest-value, lowest-risk refactorings available — no logic change, meaningful readability gain. IDE-automated rename/extract commands are safer than manual find-and-replace since they understand actual references, not just text matches.
Keep your own version of these notes — editable, searchable, and organised by your stack.
Start free