Refactoring

Claude in VS Code: Pair Programming

Chapter 3  ·  Refactoring — Improving Code with Claude

Refactoring is where Claude in VS Code earns its keep. It can rename, restructure, simplify, and modernise code — but only if you give it the right scope. Too broad and it changes more than you intended. Too narrow and it misses dependencies. This chapter covers how to scope refactors correctly, how to use the diff view to stay in control, and how to handle changes that span multiple files.

The Core Risk: Scope Creep

The most common problem with AI-assisted refactoring is that Claude improves things you didn't ask it to improve. You say "rename this variable" and get back a rewritten function. You say "simplify this method" and Claude also changes the calling code.

This isn't necessarily wrong — Claude may be right that the related code should change. But it means you're reviewing more than you planned, and changes you didn't request can introduce bugs you won't notice until later.

The solution is explicit scope constraints in every refactoring prompt.

Scoping a Refactor

Inline — single expression
Rename / simplify
Rename `usr` to `current_user` throughout this function only. Don't change anything else.
Use Ctrl+I with selection. Fastest for single-expression changes.
Function scope
Restructure logic
Refactor this function to use early returns instead of nested ifs. Keep the same inputs, outputs, and behaviour.
Select the function, send to chat. Ask Claude to confirm behaviour is unchanged.
File scope
Extract / reorganise
Extract the database logic in this file into a separate class. Keep the public interface identical — don't change how callers use it.
Use chat panel. Ask Claude to list every change it's making before doing it.
Multi-file
Rename across project
Rename the `UserController` class to `AccountController` everywhere in the project. Show me every file you'll touch before making changes.
Always preview first. Review each file diff before accepting.

Constraint Phrases That Prevent Over-reach

These phrases, added to any refactoring prompt, keep Claude within the scope you intended:

PhraseWhat it prevents
Don't change anything outside this function Claude modifying callers or related functions it thinks "should" also change
Keep the public interface identical Parameter names, return types, or method signatures being altered silently
Preserve existing behaviour exactly "Improvements" that change edge-case handling or error behaviour
Show me every file you'll touch before making changes Surprise edits to files you didn't know were affected
Only rename — don't restructure the logic Claude taking a rename request as an invitation to also clean up the surrounding code
Make the minimum change to achieve this Over-engineering or adding abstractions you didn't ask for

Using the Diff View

When Claude makes changes via the inline editor (Ctrl+I), VS Code shows the result as a diff — additions in green, removals in red — before anything is applied. This is your main safety mechanism for refactoring.

auth.py — inline refactor diff
✓ Accept ✕ Reject
def authenticate(usr, pwd):
if usr == None or pwd == None:
if usr is None or pwd is None:
return False
result = check_credentials(usr, pwd)
if result == True:
if check_credentials(usr, pwd):
return True
return False

Read the diff carefully before accepting. Ask yourself:

  • Did Claude change anything I didn't ask it to?
  • Is every removed line intentionally removed, or did something slip?
  • Are the added lines functionally equivalent to what they replace?
  • Does the diff touch code outside my selected scope?
Accept partial diffs
If Claude's diff is 90% right but one change is wrong, don't reject the whole thing — accept it, then use Ctrl+Z to undo just the specific line, or make a manual edit. Rejecting a large diff because of one line wastes all the good work.

Common Refactoring Requests

Vague
Clean this up.
Specific
Replace the nested if-else chain with early returns. Don't change the logic, just the structure.
Vague
Make this more Pythonic.
Specific
Replace the manual list-building loop with a list comprehension. Keep the filter logic identical.
Vague
Refactor this class.
Specific
Extract the three private `_parse_*` methods into a separate `Parser` class in the same file. The public API of `DataLoader` must not change.

Multi-File Refactors

Some refactors touch more than one file — renaming a class, changing a function signature, moving a module. These need more care because the diff view shows one file at a time and it's easy to miss an affected file.

📋
Plan before executing. Ask Claude: "If I rename `UserService` to `AccountService`, which files in this project would need to change?" Get the list first — don't start editing until you know the full scope.
🔍
Verify the list. Use VS Code's built-in Find in Files (Ctrl+Shift+F) to search for the old name. Compare Claude's list against the search results — if they differ, Claude missed something or the search found false positives.
✏️
Do one file at a time. Ask Claude to make the change in a single file, review the diff, accept it, then move to the next. Don't let Claude batch-edit multiple files in one response — you lose visibility.
🧪
Run tests after each file. If the project has tests, run them after each file is updated. A failing test immediately after a specific file tells you exactly where the problem is — much easier to debug than a failing test suite at the end.
Final check. After all files are done, search for the old name one more time with Ctrl+Shift+F. Any remaining hits that shouldn't be there are missed updates.
VS Code rename symbol vs Claude
For pure renames — a variable, function, or class name — VS Code's built-in Rename Symbol (F2) is often faster and more reliable than asking Claude. It uses the language server to find every reference automatically. Use Claude for renaming when the change also involves restructuring, or when the language server doesn't cover the file type.

Refactoring Patterns Claude Does Well

  • Early returns — flattening deeply nested conditionals
  • Extract method/class — pulling a coherent block of logic into its own function or class
  • Modernise syntax — updating old patterns to current language idioms (e.g. f-strings, optional chaining, pattern matching)
  • Remove duplication — identifying repeated logic and centralising it
  • Clarify naming — renaming cryptic variables and functions to descriptive names
  • Convert callback to async/await — restructuring callback-based code to async equivalents
  • Add type annotations — inferring and adding types to untyped Python or TypeScript code

Refactoring patterns Claude does poorly

  • Performance optimisation — Claude can suggest patterns but rarely knows your runtime bottleneck. Profile first, then ask Claude to apply a specific optimisation.
  • Architecture-level restructuring — moving entire modules, changing dependency direction, introducing new layers. These benefit more from a planning conversation than a direct refactoring request.
  • Database schema changes — Claude can write the migration but doesn't know your data volume, index strategy, or production constraints. Treat its output as a starting point.
Next — Chapter 4: Generating Code
Asking Claude to write new features, boilerplate, and schema from a description. How to give Claude enough context to generate code that fits your existing patterns, what to check in generated code before committing, and how to iterate when the first output isn't quite right.