DEV Community

Zac
Zac

Posted on

Refactoring with Claude Code: keeping changes clean and reviewable

Refactoring is where AI assistance most commonly goes wrong. You ask for a clean-up and get 50 file changes that are technically improvements but impossible to review, rollback, or attribute if something breaks.

Here's the approach that keeps refactoring under control.

The core constraint

Before any refactoring task:

Refactor [specific thing] to [specific goal].
Constraints:
- Do not change behavior. Only change structure.
- Do not modify public interfaces unless that is the stated goal.
- All existing tests must pass after the change with no modifications.
- Make atomic commits — one logical change per commit.
- Do not clean up adjacent code you weren't asked to touch.
Enter fullscreen mode Exit fullscreen mode

The last point prevents the biggest failure mode: Claude "improving" code on the way through.

Staged refactoring

For large refactors, break into explicit stages:

Stage 1: Extract (move code without changing it)
Stage 2: Rename (rename things after they're in the right place)
Stage 3: Clean up (remove duplication, improve names, apply patterns)

Never combine stages. "Extract and rename and clean up in one PR" is not reviewable.

The strangler fig pattern for big changes

For large-scale changes (switching ORMs, replacing an API layer, migrating a module), use the strangler fig pattern:

  1. Create the new implementation alongside the old one
  2. Route new code to the new implementation
  3. Migrate existing callers one at a time
  4. Delete the old implementation when no callers remain

This keeps the codebase working throughout. No big-bang migration.

For Claude:

Create the new [thing] at [new path]. Do not modify the old one yet. I will migrate callers separately.
Enter fullscreen mode Exit fullscreen mode

Checking scope during the refactor

After Claude makes changes, run:

git diff --name-only
Enter fullscreen mode Exit fullscreen mode

If files appear that you didn't expect, ask:

You modified [file]. That wasn't in scope for this refactor. Explain why you changed it, and if it wasn't necessary, revert it.
Enter fullscreen mode Exit fullscreen mode

Catch drift early. Files that "just needed a small fix" are scope creep.

When tests change

If Claude modifies tests during a refactor, that's a red flag. Tests should only change if:

  • The interface changed (intentionally)
  • A test was testing implementation details and now needs to test behavior

Ask explicitly: "Why did you modify this test? Show me the original and the change."

The review checklist

Before merging a refactoring PR:

  • [ ] Behavior is identical (tests prove it)
  • [ ] No new functionality was added
  • [ ] No files changed outside stated scope
  • [ ] Each commit is understandable in isolation
  • [ ] The code is simpler, not just different

Simpler is the goal. A refactor that adds complexity for extensibility you don't need is not an improvement.

More on managing Claude Code scope: builtbyzac.com/agent-harness.html.

Top comments (0)