AI-assisted refactoring: how to safely change code everyone's afraid of
Jump to section
Every codebase has that file. The one nobody wants to touch. '2000 lines, no tests, whoever wrote it no longer works here.' AI is the ideal tool for this — but only with a clear process. Without one, AI refactoring causes more damage than benefit.
Refactoring without tests is like walking a tightrope without a net. AI helps you write tests fast — and that transforms a dangerous task into a safe one.
Step 1: Understanding — map the terrain
'Analyze this file. What does it do? What are its dependencies? Where are the risks? What are the side effects?' AI maps the code, identifies inputs, outputs, and side effects. You get a map instead of a jungle.
# Prompt for pre-refactoring analysis:
Analyze src/services/order-processor.ts.
I want to know:
1. Main purpose of the file
2. All public functions and what they do
3. Dependencies on other modules
4. Side effects (DB writes, API calls, events)
5. Risky areas (missing error handling,
magic numbers, tight coupling)
6. Suggest the order to refactor in
Be concise and specific.This is critical. Before any refactoring, you must understand what the code does. AI reads the entire file in seconds and gives you an overview that would otherwise take hours.
Step 2: Safety net — tests for current state
'Write tests that capture existing behavior. I don't want to change functionality — I want to know when something breaks.' AI generates tests for the current state. Now you have an alarm system for refactoring.
Key point: these tests don't verify the code is correct. They verify behavior hasn't changed. Even if current behavior is buggy — the test will catch when it changes. That's exactly what you need.
# Prompt for safety net tests:
Write unit tests for orderProcessor.
- Test ALL existing code paths
- Include happy path, error states, edge cases
- Test current behavior (even if possibly buggy)
- Name tests descriptively:
'should return X when Y'
- After writing, RUN tests and fix failures
- DO NOT change implementation — just testTypical result: 20-40 tests in 5-10 minutes. Manually, this would take half a day to a full day. And now you have a safety net — any change that breaks existing behavior will be caught.
Step 3: Gradual changes — small, verifiable steps
Here's the key rule: NEVER refactor everything at once. Small steps, run tests after each one. AI does the mechanical work, tests verify each step.
- Typical refactoring steps (always one at a time):
- 1. Extract function from long method — run tests
- 2. Rename variables to meaningful names — run tests
- 3. Add TypeScript types — run tests
- 4. Remove dead code — run tests
- 5. Split large file into smaller modules — run tests
- 6. Replace magic numbers with constants — run tests
- 7. Add missing error handling — run tests
# Prompt for gradual refactoring:
Refactor orderProcessor. After each step
run tests. If anything fails, fix before
the next step.
Step 1: Extract calculateShipping from lines 89-145
into a separate function.
Step 2: Rename: o -> order, d -> discount,
s -> shippingCost
Step 3: Add TypeScript types to all parameters
and return values.
Step 4: Replace magic number 0.15 with constant
TAX_RATE.
ALWAYS run tests between steps.
One step = one commit.Step 4: Document the changes
After refactoring, have AI write documentation. 'Based on our work, write documentation for this module. Include: what it does, public API, known limitations, and what we changed during refactoring and why.' This captures context that would otherwise be lost.
What never to do
- 'Refactor the entire file at once' — recipe for disaster even with AI
- Refactor without tests — no safety net
- Multiple large changes in one commit — nowhere to roll back to
- Blindly trust AI output without review — AI makes subtle mistakes
- Change behavior during refactoring — refactoring = same functionality, better structure
Real results
On one project, I used this process to refactor a 3,500-line module in 2 days. AI generated 35 tests (step 2), then performed 12 refactoring steps. Each step: AI change -> run tests -> review -> commit. Result: same functionality, 60% smaller file, fully typed, with documentation.
Without AI, the same work would have taken 8-10 days. The key difference isn't that AI refactors faster — it's that AI generates the safety net (tests) in minutes instead of hours. And without a safety net, you wouldn't have dared refactor at all.
The best refactoring is boring refactoring. Small steps, tests after each one, no surprises. AI does the boring work for you — you make the decisions.
Karel Čech
Developer and AI consultant. I help technical teams adopt AI in their daily workflow — from workshops to long-term strategies.
LinkedIn →Stay ahead with AI insights
Practical tips on AI for dev teams. No spam, unsubscribe anytime.
Liked this post? Dive deeper with our course:
Related posts
AI on legacy code: how to modernize a codebase older than your team
Legacy code is where AI delivers the biggest ROI. 10,000 lines with no tests and no docs? This is exactly where AI saves weeks of work — if you know how.
AI for the whole team: shared workspaces, collective agents, and team workflows
Every developer prompts on their own. That's wasteful. AI is much more powerful when the team uses it in coordination — here's how.
Cloud agents in practice: Devin, Codex, and when a cloud AI developer makes sense
Fully autonomous AI developers in the cloud promise a lot. But they handle only specific tasks well. Here's where they work, where they don't, and how to use them effectively.
Ready to start?
Free 30-minute consultation — we'll figure out where AI can level up your team the most.
Book a free consultation