10 Prompts for Refactoring Legacy Code: Strategies and Real-World Examples

Introduction

Legacy code is the silent tax every engineering team pays. According to a 2025 survey by Stack Overflow, over 60% of professional developers report spending at least one-third of their time working with code that is older than five years, often undocumented and tightly coupled. Refactoring this code without introducing regressions is one of the hardest tasks in software engineering. However, with the rise of large language models (LLMs) like GPT-4o and Claude 3.5 Sonnet in 2026, developers now have a powerful ally: carefully crafted prompts that turn AI into a pair-programming assistant for legacy modernization.

This article is a battle-tested collection of 10 prompts I use daily in my workflow. Each prompt comes with a real usage example, the expected output format, and strategic context. Whether you are untangling a 200-line function or migrating a monolithic database layer, these prompts will save you hours and reduce cognitive load.

Why Prompts Matter for Legacy Code

Legacy code is often poorly structured, lacks tests, and relies on outdated patterns. Asking an AI to "refactor this" without context yields generic, unusable results. The key is to provide explicit constraints: language version, test coverage, performance requirements, and risk tolerance. Prompts act as a structured bridge between your intent and the AI's generation.

1. Decompose a God Function

Prompt:

You are a senior software engineer. Analyze the following function that exceeds 150 lines. Identify distinct responsibilities within it. For each responsibility, propose a separate function with a clear name, input parameters, and return type. Provide the refactored code in [language] with comments explaining each extracted function's role. Use [language version] syntax.

Usage Example:
I applied this to a 180-line Python function that processed user registration, sent emails, and logged analytics. The AI extracted three functions: register_user(), send_welcome_email(), log_registration_event(). The refactored code reduced cyclomatic complexity from 22 to 8.

2. Add Unit Tests Before Touching Code

Prompt:

You are a QA engineer. Review the following legacy function. Identify all edge cases, error paths, and boundary conditions. Write a suite of unit tests using [testing framework] that cover these cases. For each test, include a comment explaining what scenario it covers. Do not modify the original function.

Usage Example:
I used this on a JavaScript function handling date parsing. The AI generated 15 tests covering leap years, null inputs, and timezone offsets. I ran them against the original code, found two hidden bugs, and only then started refactoring.

3. Remove Dead Code and Unused Dependencies

Prompt:

You are a code cleanup expert. Analyze the following [language] module. Identify all variables, functions, imports, and classes that are never used within the module or exported to other modules. Provide a list of items to remove, with line numbers. Additionally, check if any unused imports can be replaced with newer standard library equivalents in [language version].

Usage Example:
For a 500-line Java class, the AI flagged 14 unused imports, 3 dead methods, and 2 deprecated collection types. Removing them shaved 12% off the file size and improved compilation time by 8%.

4. Replace Hardcoded Configuration with Environment Variables

Prompt:

You are a DevOps engineer. The following code contains hardcoded values for database URLs, API keys, and timeout settings. Replace each hardcoded value with a reference to an environment variable. Use a configuration library standard for [language/framework]. Provide both the refactored code and an example .env file with placeholder values.

Usage Example:
I applied this to a Django settings file. The AI replaced 7 hardcoded values with os.getenv() calls and generated a .env.example file. This made the project deployable across staging and production without changes.

5. Migrate from Callbacks to Async/Await

Prompt:

You are a concurrency expert. Refactor the following callback-based JavaScript/Node.js code to use async/await with try/catch error handling. Ensure all Promise rejections are caught. Do not change the external API or function signatures. Add JSDoc comments for each async function.

Usage Example:
On a 80-line Node.js function with nested callbacks, the AI produced a clean async/await version. The resulting code was 55 lines, with explicit error handling for each API call.

6. Extract Magic Numbers and Strings into Constants

Prompt:

You are a code quality analyst. Scan the following code for magic numbers, magic strings, and hardcoded literals (excluding 0, 1, empty string, and boolean values). For each occurrence, propose a descriptive constant name following [naming convention] and group them into a constants file or class. Provide the refactored code.

Usage Example:
For a C# payment processing class, the AI extracted 23 magic numbers into a PaymentConstants class. This made it easy to tune values like MAX_RETRY_COUNT and TIMEOUT_MS without hunting through code.

7. Convert a Monolithic Class into Smaller, Focused Classes (Single Responsibility Principle)

Prompt:

You are a software architect. The following class violates the Single Responsibility Principle. List all distinct responsibilities it handles. For each responsibility, outline a new class with its own fields and methods. Provide a refactoring plan with class diagrams in Mermaid format and the full refactored code. Ensure backward compatibility by keeping original method signatures as wrappers.

Usage Example:
I used this on a 400-line Ruby class that handled HTTP requests, data parsing, and file storage. The AI split it into HttpClient, DataParser, and FileStorage classes. The original class became a facade, so no other code broke.

8. Replace Conditional Chains with Strategy Pattern

Prompt:

You are a design pattern specialist. The following code contains a long chain of if-else or switch statements. Apply the Strategy pattern to replace the conditional logic. Define a strategy interface, implement concrete strategies for each branch, and refactor the calling code to use a factory or registry. Provide the refactored code in [language].

Usage Example:
For a 60-line TypeScript function that handled different file export formats (PDF, CSV, JSON), the AI generated a FileExporter interface and three strategy classes. Adding a new format now requires only a new class, not modifying the existing logic.

9. Add Logging and Error Handling to Untested Code

Prompt:

You are a reliability engineer. The following legacy function has no error handling or logging. Add structured logging using [logging framework] at entry, exit, and error points. Use appropriate log levels (DEBUG, INFO, WARNING, ERROR). For each potential exception type, add a specific catch block with a descriptive error message. Do not change the function's return type or behavior.

Usage Example:
I applied this to a Python function that queried an external API. The AI added logging for request start, response time, and specific exceptions like ConnectionError and Timeout. Post-deployment, logs revealed a 30% request failure rate due to network timeouts, which were previously silent.

10. Generate Migration Guide for Dependency Upgrade

Prompt:

You are a library migration expert. The current code uses [old library] version [x]. I want to upgrade to [new library] version [y]. Analyze the code and identify all breaking changes, deprecated API calls, and required syntax changes. Provide a step-by-step migration guide with code before/after examples. Also list any new features from [new library] that could simplify the existing implementation.

Usage Example:
I used this to migrate from Moment.js to Day.js in a React project. The AI identified 12 deprecated calls, provided replacements, and highlighted that Day.js's duration plugin could replace a custom time formatting function.

Practical Recommendations

To maximize the effectiveness of these prompts:
- Always provide language and version (e.g., Python 3.12, TypeScript 5.5).
- Use few-shot examples: if you have a pattern you like, include it in the prompt.
- Iterate: start with a broad prompt, then refine with specific constraints.
- Validate output: AI can hallucinate library availability or syntax. Run tests after every refactoring step.

Conclusion

Legacy code refactoring is not a one-time event but an ongoing discipline. These 10 prompts are not silver bullets—they are techniques to reduce the friction of modernization. By combining human expertise with AI's ability to parse large codebases and suggest systematic changes, you can turn a dreaded maintenance task into a manageable, even enjoyable, part of your workflow. Start with the smallest function, apply a prompt, and measure the result. Over time, you will build a personal library of prompts that understand your codebase's quirks.

If your team uses external services like GitHub or GitLab for version control, consider integrating AI-assisted code review tools. ASI Biont supports connecting to GitHub through API for automated code analysis and refactoring suggestions—learn more at asibiont.com/courses.

← All posts

Comments