Legacy Code Review and Refactoring Plan
Core Philosophy
Legacy code review is not just about finding bugs—it's about understanding the original intent, reducing technical debt, and incrementally modernizing while maintaining stability. Apply the principle: "Make it work, make it right, make it fast" in that order.
Instructions
1. Discovery & Analysis
Use Read, Grep, and Glob tools to:
- Identify files referenced by the user
- Search for deprecated APIs, patterns, or libraries (e.g.,
collections.MutableMapping → collections.abc.MutableMapping)
- Detect code smells:
- Unused imports/functions (candidates for deletion)
- Duplicated code blocks (refactor to DRY)
- High cyclomatic complexity (McCabe > 10)
- Missing type hints (Python) or JSDoc (JavaScript)
2. Modern Tooling Recommendations
Python Legacy Code (2024-2025 Best Practices):
| Tool |
Purpose |
Usage |
| Ruff |
Ultra-fast linter + formatter (replaces Flake8, Black, isort) |
ruff check --fix . |
| Vulture |
Dead code detection |
vulture src/ |
| Refurb |
Suggests modern Python idioms |
refurb check src/ |
| mypy |
Static type checking |
mypy --strict src/ |
| Bandit |
Security vulnerability scanner |
bandit -r src/ |
| Radon |
Complexity metrics |
radon cc -s src/ |
| pytest + coverage |
Test coverage analysis |
pytest --cov=src tests/ |
JavaScript/TypeScript Legacy Code:
| Tool |
Purpose |
Usage |
ESLint (with eslint-plugin-deprecation) |
Detect deprecated APIs |
eslint --fix . |
| Prettier |
Code formatting |
prettier --write . |
| TypeScript Compiler |
Type checking for TS/JS |
tsc --noEmit |
| ts-prune |
Dead code detection |
ts-prune |
| SonarQube |
Multi-language code quality |
CI/CD integration |
AI-Powered Code Review (GitHub Integration):
| Tool |
Key Feature |
| GitHub Copilot |
Suggests refactorings, generates tests, explains legacy functions |
| CodeRabbit |
Full codebase context-aware reviews in PRs |
| Qodo.ai (Codium) |
AI test generation and quality checks |
| DeepSource |
Security + performance analysis |
| Greptile |
Semantic code search across large repos |
3. Refactoring Process (Step-by-Step)
[!IMPORTANT]
Always write tests BEFORE refactoring. If no tests exist, create characterization tests first.
Understand the Intent
- Ask: "What problem was this solving?"
- Review git history:
git log --follow <file> and git blame <file>
- Document assumptions in code comments
Establish Safety Nets
- Run existing tests:
pytest tests/ (Python) or npm test (JS)
- Measure current coverage:
pytest --cov → target 80%+ for critical paths
- Add characterization tests if coverage < 60%
Incremental Refactoring (Layer by Layer)
- Phase 1: Fix linting/formatting (Ruff, Prettier) — low risk
- Phase 2: Add type hints (mypy, TypeScript) — medium risk
- Phase 3: Extract functions, reduce complexity — medium risk
- Phase 4: Replace deprecated APIs with modern equivalents — high risk
- Phase 5: Extract to new modules (strangler fig pattern) — high risk
Verification Gates
- All existing tests pass (
pytest, npm test)
- No new linting errors (
ruff check, eslint)
- Code coverage unchanged or improved (
pytest --cov)
- Security scan passes (
bandit, npm audit)
Documentation
- Update docstrings with modern examples
- Add inline comments explaining why, not what
- Create migration guide if API changes affect users
4. Common Legacy Code Patterns (Python)
| Deprecated |
Modern Replacement |
Reason |
from collections import MutableMapping |
from collections.abc import MutableMapping |
Moved in Python 3.3+ |
os.path.join(a, b) |
pathlib.Path(a) / b |
Type-safe, cleaner API |
% formatting |
f"{variable}" or str.format() |
More readable, faster |
try/except without context |
with contextlib.suppress(Exception): |
Cleaner error handling |
dict.has_key(k) |
k in dict |
Pythonic, removed in Py3 |
| No type hints |
def func(x: int) -> str: |
Catches bugs at dev time |
5. GitHub Pull Request Best Practices (2024-2025)
[!TIP]
Keep PRs small (<400 lines) for faster, more accurate reviews.
- Small PRs: Break large refactors into atomic changes
- Self-Review First: Review your own PR before requesting others
- Automated Checks: Enforce linting, tests, security scans in CI/CD
- Clear Descriptions: Explain what, why, impact, how tested
- Use Draft PRs: For work-in-progress, get early feedback
- Feature Flags: For risky changes, use toggles to A/B test old vs new logic
Output Format
Provide the following in your review:
Summary of Findings
- List deprecated patterns found (with line numbers)
- Complexity metrics (if applicable)
- Security vulnerabilities (if any)
Recommended Tooling
- Specific commands to run (e.g.,
ruff check --fix src/)
- Expected output/improvements
Refactoring Plan (Phased)
- Phase 1: Low-risk fixes (formatting, linting)
- Phase 2: Medium-risk (type hints, small extractions)
- Phase 3: High-risk (API migrations, architectural changes)
Example Code Block
- Show before and after code
- Include comments explaining the change
- Demonstrate modern conventions
Example Usage
User Request:
"Can you review @src/legacy/old_database_connector.py and suggest how to update it for better performance and maintainability?"
Agent Response:
Summary of Findings
- Line 23: Using deprecated
collections.MutableMapping (should be collections.abc.MutableMapping)
- Line 45-67: Database connection logic duplicated 3 times (DRY violation)
- Line 89: No type hints, making debugging difficult
- Complexity: McCabe score of 15 (threshold is 10)
Recommended Tooling
# Run modern linters
ruff check --fix src/legacy/old_database_connector.py
mypy src/legacy/old_database_connector.py
bandit -r src/legacy/
# Check complexity
radon cc -s src/legacy/old_database_connector.py
Refactoring Plan
Phase 1 (Low Risk):
- Fix import:
collections.MutableMapping → collections.abc.MutableMapping
- Run Ruff to auto-fix formatting/linting
Phase 2 (Medium Risk):
- Add type hints to all functions
- Extract duplicated connection logic to
_get_db_connection() helper
Phase 3 (High Risk):
- Replace raw SQL with SQLAlchemy ORM (if applicable)
- Implement connection pooling for performance
Example Refactoring
Before (Legacy):
from collections import MutableMapping # DEPRECATED
def connect_db(host, port):
conn = psycopg2.connect(host=host, port=port) # Duplicated 3 times
return conn
After (Modern):
from collections.abc import MutableMapping
from typing import Optional
import psycopg2
from psycopg2 import pool
# Connection pool (shared resource)
_connection_pool: Optional[pool.SimpleConnectionPool] = None
def get_db_connection(host: str, port: int) -> psycopg2.extensions.connection:
"""
Get a database connection from the pool.
Args:
host: Database host (e.g., 'localhost')
port: Database port (e.g., 5432)
Returns:
Active database connection
Raises:
psycopg2.OperationalError: If connection fails
"""
global _connection_pool
if _connection_pool is None:
_connection_pool = pool.SimpleConnectionPool(
minconn=1, maxconn=10, host=host, port=port
)
return _connection_pool.getconn()
Key Improvements:
- ✅ Fixed deprecated import
- ✅ Added type hints (
str, int, psycopg2.extensions.connection)
- ✅ Extracted to single function (DRY)
- ✅ Implemented connection pooling (performance)
- ✅ Added comprehensive docstring
Verification Checklist
Before marking refactoring complete:
Additional Resources
1---2name: legacy-code-reviewer3description: Expert system for identifying deprecated patterns, suggesting refactoring to modern standards (Python 3.12+, ES2024+), checking test coverage, and leveraging AI-powered tools. Proactively applied when users request refactoring, updates, or analysis of legacy codebases.4---5
6# Legacy Code Review and Refactoring Plan
7
8## Core Philosophy
9
10Legacy code review is not just about finding bugs—it's about understanding the **original intent**, reducing technical debt, and incrementally modernizing while maintaining stability. Apply the principle: *"Make it work, make it right, make it fast"* in that order.
11
12---
13
14## Instructions
15
16### 1. Discovery & Analysis
17
18**Use Read, Grep, and Glob tools to:**
19- Identify files referenced by the user
20- Search for deprecated APIs, patterns, or libraries (e.g., `collections.MutableMapping` → `collections.abc.MutableMapping`)
21- Detect code smells:
22 - Unused imports/functions (candidates for deletion)
23 - Duplicated code blocks (refactor to DRY)
24 - High cyclomatic complexity (McCabe > 10)
25 - Missing type hints (Python) or JSDoc (JavaScript)
26
27### 2. Modern Tooling Recommendations
28
29**Python Legacy Code (2024-2025 Best Practices):**
30
31| Tool | Purpose | Usage |
32|------|---------|-------|
33| **Ruff** | Ultra-fast linter + formatter (replaces Flake8, Black, isort) | `ruff check --fix .` |
34| **Vulture** | Dead code detection | `vulture src/` |
35| **Refurb** | Suggests modern Python idioms | `refurb check src/` |
36| **mypy** | Static type checking | `mypy --strict src/` |
37| **Bandit** | Security vulnerability scanner | `bandit -r src/` |
38| **Radon** | Complexity metrics | `radon cc -s src/` |
39| **pytest** + **coverage** | Test coverage analysis | `pytest --cov=src tests/` |
40
41**JavaScript/TypeScript Legacy Code:**
42
43| Tool | Purpose | Usage |
44|------|---------|-------|
45| **ESLint** (with `eslint-plugin-deprecation`) | Detect deprecated APIs | `eslint --fix .` |
46| **Prettier** | Code formatting | `prettier --write .` |
47| **TypeScript Compiler** | Type checking for TS/JS | `tsc --noEmit` |
48| **ts-prune** | Dead code detection | `ts-prune` |
49| **SonarQube** | Multi-language code quality | CI/CD integration |
50
51**AI-Powered Code Review (GitHub Integration):**
52
53| Tool | Key Feature |
54|------|-------------|
55| **GitHub Copilot** | Suggests refactorings, generates tests, explains legacy functions |
56| **CodeRabbit** | Full codebase context-aware reviews in PRs |
57| **Qodo.ai (Codium)** | AI test generation and quality checks |
58| **DeepSource** | Security + performance analysis |
59| **Greptile** | Semantic code search across large repos |
60
61### 3. Refactoring Process (Step-by-Step)
62
63> [!IMPORTANT]
64> **Always write tests BEFORE refactoring. If no tests exist, create characterization tests first.**
65
661. **Understand the Intent**
67 - Ask: "What problem was this solving?"
68 - Review git history: `git log --follow <file>` and `git blame <file>`
69 - Document assumptions in code comments
70
712. **Establish Safety Nets**
72 - Run existing tests: `pytest tests/` (Python) or `npm test` (JS)
73 - Measure current coverage: `pytest --cov` → target 80%+ for critical paths
74 - Add characterization tests if coverage < 60%
75
763. **Incremental Refactoring (Layer by Layer)**
77 - **Phase 1:** Fix linting/formatting (Ruff, Prettier) — *low risk*
78 - **Phase 2:** Add type hints (mypy, TypeScript) — *medium risk*
79 - **Phase 3:** Extract functions, reduce complexity — *medium risk*
80 - **Phase 4:** Replace deprecated APIs with modern equivalents — *high risk*
81 - **Phase 5:** Extract to new modules (strangler fig pattern) — *high risk*
82
834. **Verification Gates**
84 - All existing tests pass (`pytest`, `npm test`)
85 - No new linting errors (`ruff check`, `eslint`)
86 - Code coverage unchanged or improved (`pytest --cov`)
87 - Security scan passes (`bandit`, `npm audit`)
88
895. **Documentation**
90 - Update docstrings with modern examples
91 - Add inline comments explaining **why**, not **what**
92 - Create migration guide if API changes affect users
93
94### 4. Common Legacy Code Patterns (Python)
95
96| Deprecated | Modern Replacement | Reason |
97|-----------|-------------------|--------|
98| `from collections import MutableMapping` | `from collections.abc import MutableMapping` | Moved in Python 3.3+ |
99| `os.path.join(a, b)` | `pathlib.Path(a) / b` | Type-safe, cleaner API |
100| `% formatting` | `f"{variable}"` or `str.format()` | More readable, faster |
101| `try/except` without context | `with contextlib.suppress(Exception):` | Cleaner error handling |
102| `dict.has_key(k)` | `k in dict` | Pythonic, removed in Py3 |
103| No type hints | `def func(x: int) -> str:` | Catches bugs at dev time |
104
105### 5. GitHub Pull Request Best Practices (2024-2025)
106
107> [!TIP]
108> **Keep PRs small (<400 lines) for faster, more accurate reviews.**
109
110- **Small PRs:** Break large refactors into atomic changes
111- **Self-Review First:** Review your own PR before requesting others
112- **Automated Checks:** Enforce linting, tests, security scans in CI/CD
113- **Clear Descriptions:** Explain **what**, **why**, **impact**, **how tested**
114- **Use Draft PRs:** For work-in-progress, get early feedback
115- **Feature Flags:** For risky changes, use toggles to A/B test old vs new logic
116
117---
118
119## Output Format
120
121### Provide the following in your review:
122
1231. **Summary of Findings**
124 - List deprecated patterns found (with line numbers)
125 - Complexity metrics (if applicable)
126 - Security vulnerabilities (if any)
127
1282. **Recommended Tooling**
129 - Specific commands to run (e.g., `ruff check --fix src/`)
130 - Expected output/improvements
131
1323. **Refactoring Plan (Phased)**
133 - Phase 1: Low-risk fixes (formatting, linting)
134 - Phase 2: Medium-risk (type hints, small extractions)
135 - Phase 3: High-risk (API migrations, architectural changes)
136
1374. **Example Code Block**
138 - Show **before** and **after** code
139 - Include comments explaining the change
140 - Demonstrate modern conventions
141
142---
143
144## Example Usage
145
146**User Request:**
147> "Can you review `@src/legacy/old_database_connector.py` and suggest how to update it for better performance and maintainability?"
148
149**Agent Response:**
150
151### Summary of Findings
152- **Line 23:** Using deprecated `collections.MutableMapping` (should be `collections.abc.MutableMapping`)
153- **Line 45-67:** Database connection logic duplicated 3 times (DRY violation)
154- **Line 89:** No type hints, making debugging difficult
155- **Complexity:** McCabe score of 15 (threshold is 10)
156
157### Recommended Tooling
158```bash
159# Run modern linters
160ruff check --fix src/legacy/old_database_connector.py
161mypy src/legacy/old_database_connector.py
162bandit -r src/legacy/
163
164# Check complexity
165radon cc -s src/legacy/old_database_connector.py
166```
167
168### Refactoring Plan
169**Phase 1 (Low Risk):**
170- Fix import: `collections.MutableMapping` → `collections.abc.MutableMapping`
171- Run Ruff to auto-fix formatting/linting
172
173**Phase 2 (Medium Risk):**
174- Add type hints to all functions
175- Extract duplicated connection logic to `_get_db_connection()` helper
176
177**Phase 3 (High Risk):**
178- Replace raw SQL with SQLAlchemy ORM (if applicable)
179- Implement connection pooling for performance
180
181### Example Refactoring
182
183**Before (Legacy):**
184```python
185from collections import MutableMapping # DEPRECATED
186
187def connect_db(host, port):
188 conn = psycopg2.connect(host=host, port=port) # Duplicated 3 times
189 return conn
190```
191
192**After (Modern):**
193```python
194from collections.abc import MutableMapping
195from typing import Optional
196import psycopg2
197from psycopg2 import pool
198
199# Connection pool (shared resource)
200_connection_pool: Optional[pool.SimpleConnectionPool] = None
201
202def get_db_connection(host: str, port: int) -> psycopg2.extensions.connection:
203 """
204 Get a database connection from the pool.
205
206 Args:
207 host: Database host (e.g., 'localhost')
208 port: Database port (e.g., 5432)
209
210 Returns:
211 Active database connection
212
213 Raises:
214 psycopg2.OperationalError: If connection fails
215 """
216 global _connection_pool
217 if _connection_pool is None:
218 _connection_pool = pool.SimpleConnectionPool(
219 minconn=1, maxconn=10, host=host, port=port
220 )
221 return _connection_pool.getconn()
222```
223
224**Key Improvements:**
225- ✅ Fixed deprecated import
226- ✅ Added type hints (`str`, `int`, `psycopg2.extensions.connection`)
227- ✅ Extracted to single function (DRY)
228- ✅ Implemented connection pooling (performance)
229- ✅ Added comprehensive docstring
230
231---
232
233## Verification Checklist
234
235Before marking refactoring complete:
236
237- [ ] All existing tests pass
238- [ ] Linting passes (`ruff check`, `eslint`)
239- [ ] Type checking passes (`mypy`, `tsc`)
240- [ ] Security scan clean (`bandit`, `npm audit`)
241- [ ] Code coverage maintained or improved
242- [ ] Documentation updated
243- [ ] PR reviewed by at least one peer
244- [ ] Manual testing performed (if applicable)
245
246---
247
248## Additional Resources
249
250- [GitHub Copilot for Legacy Code](https://github.blog/2024-01-22-10-unexpected-ways-to-use-github-copilot/)
251- [Refactoring Guru (Design Patterns)](https://refactoring.guru/)
252- [Python Type Hints Cheat Sheet](https://mypy.readthedocs.io/en/stable/cheat_sheet_py3.html)
253- [Google's Code Review Best Practices](https://google.github.io/eng-practices/review/)