Refactoring legacy code is like performing surgery on a patient who's been awake for years—every move risks breaking something, and the patient (your production system) doesn't appreciate your efforts. Our team felt this pain daily: weeks spent untangling spaghetti code, deciphering undocumented functions, and fearing the next deployment. Then we discovered a game-changer: using AI with carefully crafted prompts. This isn't about replacing developers; it's about supercharging our workflow. In this article, I'll share 12 prompts that helped us cut refactoring time in half. These aren't theoretical—they're battle-tested in real projects, from Python backend services to JavaScript frontend monsters.
The Problem: Legacy Code Nightmares
Legacy code often lacks tests, has cryptic variable names, and follows no consistent style. Our team inherited a Python Django monolith with a 10,000-line views.py file and a JavaScript frontend with callback pyramids of doom. Refactoring meant hours of manual analysis, risky changes, and constant regression bugs. We needed a systematic approach.
The Solution: AI-Powered Refactoring Prompts
We integrated an AI assistant into our daily workflow, but the key was learning to communicate effectively. Generic prompts like "refactor this code" yielded generic results. Instead, we developed specific prompts that target different aspects of refactoring: understanding, decomposition, optimization, and testing. Below are the prompts that worked wonders.
1. Analyze Code Structure and Dependencies
Prompt:
Analyze the following Python/JavaScript code and provide:
1. A high-level overview of its responsibilities.
2. A list of all functions/classes and their dependencies.
3. Identify any circular dependencies or code smells.
4. Propose a module breakdown that would improve maintainability.
Code:
[PASTE CODE]
Why it works: This prompt forces the AI to act as a code reviewer, producing a structured analysis that guides your refactoring plan. In our experience, it surfaced hidden dependencies we'd missed.
Real example: For a 200-line Python function handling both database queries and HTTP requests, the AI suggested splitting it into separate repository and service layers—a classic refactoring pattern.
2. Identify and Explain Code Smells
Prompt:
Identify code smells in the following code. For each, explain why it's problematic and suggest a concrete refactoring technique (e.g., Extract Method, Replace Conditional with Polymorphism). Prioritize by impact on maintainability.
Code:
[PASTE CODE]
Why it works: This not only finds issues but educates the team. We used it on a legacy JavaScript module with multiple nested if-else conditions; the AI suggested replacing them with a strategy pattern, making the code more testable.
3. Generate Unit Tests for Legacy Code
Prompt:
Write unit tests for the following function using [pytest/Jest]. Cover edge cases, error paths, and typical inputs. Assume the function is part of a legacy system and may have hidden dependencies—mock them appropriately.
Function code:
[PASTE CODE]
Why it works: Testing legacy code is daunting, but AI can generate a test scaffold quickly. This gave us the safety net we needed to refactor with confidence. We used Jest for a JavaScript utility that formatted dates; the tests caught a timezone bug that had been lurking for years.
4. Decompose God Objects
Prompt:
This class is a "God object" — it does too much. Break it down into smaller, single-responsibility classes. Show the refactored code for each new class, and explain how they interact. Maintain backward compatibility as much as possible.
Class code:
[PASTE CODE]
Why it works: God objects are common in legacy code. The AI proposed a partition based on responsibilities, which we then refined. In one case, a Python class handling user authentication, email sending, and logging was split into three focused classes, each with clear interfaces.
5. Migrate from Callbacks to Async/Await
Prompt:
Convert the following callback-based JavaScript code to async/await. Preserve error handling semantics. Show the refactored code, and point out any potential pitfalls (e.g., concurrent execution changes).
Code:
[PASTE CODE]
Why it works: This is a common modernization task. The AI handled the mechanical conversion, but we had to manually review to ensure no behavior changed. We used it on a legacy API client with nested callbacks; the resulting async/await code was far more readable.
6. Optimize SQL Queries in Python Code
Prompt:
Review the following Python code that interacts with a database. Identify N+1 query problems, missing indexes, or inefficient joins. Suggest optimized queries using SQLAlchemy ORM or raw SQL, and show the refactored code.
Code:
[PASTE CODE]
Why it works: Legacy ORM usage often leads to performance issues. The AI suggested using selectinload to eager-load relationships, reducing queries from dozens to a handful. We saw a 3x speedup in an endpoint that listed orders.
7. Convert Python 2 to Python 3
Prompt:
Convert this Python 2 code to Python 3. Pay attention to changes like print statements, integer division, and exception syntax. Use `2to3` conventions, but also suggest modern idioms (e.g., f-strings). Show the converted code.
Code:
[PASTE CODE]
Why it works: Though Python 2 is EOL, some legacy systems still run it. This prompt saved us hours of manual conversion. We used it on a data processing script; the AI even caught a subtle bug where dict.iteritems() needed to become dict.items().
8. Refactor CSS and JavaScript for Performance
Prompt:
Analyze the following JavaScript and CSS for performance bottlenecks. Suggest concrete optimizations: debouncing, lazy loading, reducing reflows, minifying, etc. Show code changes.
Code:
[PASTE CODE]
Why it works: Frontend legacy code often has performance issues. The AI identified unnecessary DOM manipulations and suggested batch updates. We applied this to a dashboard with dozens of charts; load time dropped by 40%.
9. Extract Reusable Components (React/Vue)
Prompt:
This React/Vue component is too large and mixes data fetching with rendering. Extract reusable subcomponents and custom hooks (React) or composables (Vue). Show the refactored code.
Component code:
[PASTE CODE]
Why it works: Component bloat is common in legacy frontends. The AI proposed a split into a container component and presentational components, plus a custom hook for data fetching. This made the code easier to test and reuse.
10. Generate API Documentation from Code
Prompt:
Generate API documentation for the following Python/JavaScript module. Use docstring/JSDoc format. Include parameter descriptions, return values, exceptions, and a usage example.
Code:
[PASTE CODE]
Why it works: Legacy code often lacks documentation. AI-generated docs, while needing review, provided a starting point. We used this for a Python utility library, and the generated docs helped onboarding new developers.
11. Refactor to Use Modern Language Features
Prompt:
Refactor this JavaScript code to use ES6+ features: arrow functions, destructuring, template literals, `let/const`, and classes. Ensure behavior is unchanged.
Code:
[PASTE CODE]
Why it works: Modernization without changing behavior is a safe refactoring step. The AI handled mechanical changes, but we manually checked for scope issues with arrow functions (e.g., this binding). This made the code more concise and readable.
12. Write a Migration Plan for a Large Refactoring
Prompt:
Given this legacy module, propose a step-by-step refactoring plan that can be done incrementally without breaking the system. Include: phases, risk assessment, testing strategy, and rollback plan.
Module code:
[PASTE CODE]
Why it works: For large refactorings, having a plan is crucial. The AI outlined a strategy using the Strangler Fig pattern: gradually replace parts of the module while maintaining a facade. This gave us confidence to proceed.
Results and Lessons Learned
We adopted these prompts over a two-month sprint. The result: our velocity on refactoring tasks doubled, as measured by story points completed per sprint. More importantly, regression bugs dropped significantly because we had better test coverage generated by AI. But we also learned:
- AI is a partner, not a replacement. We always review AI-generated code for correctness and style.
- Context is king. The more specific the prompt, the better the output. Always include code snippets and mention the language/framework.
- Iterate. If the first output isn't perfect, refine the prompt or ask follow-up questions.
Try It Yourself
Start with one small legacy module and apply the prompts above. You'll likely see immediate improvements in code readability and maintainability. And as you gain trust, you can tackle larger refactorings. The key is to start small, test thoroughly, and let AI handle the grunt work while you focus on architecture decisions.
If you've used similar prompts, share your experience in the comments!
Comments