headroom.walls.sh · refactor

Refactoring with Claude Code

Large refactors are where Claude Code earns its keep. It can read a whole module, understand the patterns, plan a coherent transformation, make every edit, and run the tests to verify — while you do something else. This page covers the workflows that produce reliable results and the budget traps to avoid.

Why refactors are a natural fit

Refactors are hard for humans because they require holding the whole system in mind while making many small, consistent edits. Claude Code's context window can hold a full module; its tool calls can grep for every usage, edit every occurrence, and run the test suite to verify. The combination is more reliable than doing it by hand because Claude Code doesn't get tired and doesn't miss occurrences.

The rename-across-files pattern

The most common refactor: rename a function, class, or variable everywhere it appears.

Rename the function calculateTax to computeTaxAmount across the entire codebase.
Update all call sites, imports, and any JSDoc or comments that reference the old name.
Run the tests after and confirm they pass.

Claude Code will grep for all occurrences, read each file, make the edits, and run your tests. For a rename that spans 20 files, this takes 2–3 minutes unattended vs. 30 minutes of careful find-and-replace.

Tip: Including "run the tests after and confirm they pass" in your prompt ensures Claude Code verifies its own work. Without it, it may stop after editing. Always close the loop explicitly.

Extracting a repeated pattern

When you have similar logic duplicated across files, Claude Code can find all instances and extract them into a shared utility:

There is a pattern of fetching a user and then checking if they are active that
appears in at least 5 different route handlers. Find all instances of this pattern,
extract it into a new function getUserIfActive(userId) in src/utils/auth.ts,
replace all call sites with the new function, and run the tests.

The prompt describes the pattern by intent, not by exact code — Claude Code reads the files to find the actual occurrences. Describing intent is more robust than writing regex.

Interface / type migration

Migrating from one data shape to another (e.g., API response format changed, database schema updated) is one of the most tedious manual refactors. Describe the before and after shapes:

The API now returns { user: { id, name, email } } instead of { userId, userName, userEmail }.
Update all places in the frontend that destructure or access these fields to use the new shape.
The relevant files are in src/api/, src/components/, and src/hooks/.
Run the TypeScript compiler after to confirm there are no type errors.

Using tsc --noEmit as the verification step is particularly effective for type migrations — TypeScript's compiler catches every missed call site.

Module reorganization

Moving code between files while keeping imports working:

Move the validation functions (validateEmail, validatePhone, validatePostalCode)
from src/utils.ts into a new file src/validation.ts.
Update all import statements across the codebase to import from the new location.
The old utils.ts should no longer export these functions.
Run the build to verify no broken imports.

The explicit "run the build to verify" step is essential here — broken imports don't always surface in tests.

Staged refactors for large codebases

For a refactor that touches more than 30 files, break it into stages. Large single-step refactors can exhaust Claude Code's context or produce inconsistent edits when the scope is too wide:

Stage 1: Refactor only src/auth/ — update the interfaces and all internal call sites.
Run the auth tests and confirm they pass. Do not touch any other directories yet.
Stage 2 (after Stage 1 passes): Now propagate the new auth interface to src/api/
and src/middleware/. The auth module is already updated; match it.

Staged refactors also produce cleaner git history — each stage is a reviewable commit.

Session budget note: Large refactors are the second-fastest way to drain your 5h rolling window (after automated test loops). A refactor touching 25 files involves 25+ file reads, 25+ edits, plus test runs — easily 80–120 tool calls. At heavy use, that's 25–35% of a session window. Start large refactors at low utilization, not when you're already at 60%.

Preserving tests through a refactor

The best refactors keep tests green the whole way through. Give Claude Code explicit instructions to maintain test coverage:

Refactor the authentication module to use a class-based design instead of
standalone functions. The public API surface must remain identical — all existing
tests must continue to pass without modification. Do not change any test files.

The constraint "do not change any test files" forces Claude Code to make the refactor backward-compatible. If it can't keep tests passing without changing them, it'll tell you — and that's useful information.

Incremental verification

For refactors where you want to review as you go rather than all at once:

Refactor src/auth/token.ts only. Show me what changes you plan to make before
making them. Wait for my approval before proceeding.

This turns a fully autonomous refactor into a supervised one. Useful when the codebase has subtle invariants you don't trust Claude Code to know about.

Know your headroom before a large refactor

Large refactors are some of the most session-intensive Claude Code tasks. Starting a multi-file refactor when you're already at 70% utilization means you may not finish before the 5h window cuts you off mid-edit. Headroom shows your current session and weekly usage in the menu bar.

brew install --cask patwalls/tap/headroom

Direct download · About Headroom · Source on GitHub


Debugging with Claude Code
Agent mode — autonomous task loops
5-hour session limit explained
Claude Code tips and tricks