Agent skill
legacy-modernizer
Modernize legacy code safely in ANY project without breaking existing functionality
Install this agent skill to your Project
npx add-skill https://github.com/j0KZ/mcp-agents/tree/main/starter-kit/template/.claude/skills/legacy-modernizer
SKILL.md
Legacy Modernizer - Safe Legacy Code Evolution
🎯 When to Use This Skill
Use when dealing with:
- Code written 5+ years ago
- No tests or documentation
- "Don't touch - it works" code
- Deprecated dependencies
- Security vulnerabilities in old code
- Performance issues in legacy systems
⚡ The Golden Rule of Legacy Code
NEVER refactor without tests! First make it testable, then make it better.
📋 The Safe Modernization Process
Phase 1: UNDERSTAND (Don't Touch Yet!)
WITH MCP Tools:
"Analyze the architecture and dependencies of [legacy module]"
"Document how this legacy code works"
WITHOUT MCP:
1. Map the Territory:
# Find all files related to the feature
grep -r "LegacyClass" --include="*.js" --include="*.py" --include="*.java"
# Trace execution flow
echo "=== LEGACY CODE MAP ===" > legacy_analysis.md
echo "Entry points:" >> legacy_analysis.md
grep -r "main\|init\|start" --include="*.js" >> legacy_analysis.md
# Find dependencies
echo "Dependencies:" >> legacy_analysis.md
grep -r "require\|import\|include" legacy_module/ >> legacy_analysis.md
2. Document Current Behavior:
// Add temporary logging to understand flow
function legacyFunction(data) {
console.log('[LEGACY TRACE] Input:', JSON.stringify(data));
// ... existing code ...
console.log('[LEGACY TRACE] Output:', result);
return result;
}
Phase 2: PROTECT (Add Safety Net)
WITH MCP (Test Generator):
"Generate characterization tests for this legacy code"
WITHOUT MCP:
Characterization Tests (Capture Current Behavior):
// Not testing if it's "right", just what it currently does
describe('Legacy System - Current Behavior', () => {
it('should handle normal input as currently implemented', () => {
const result = legacyFunction({ id: 1, name: 'test' });
// Capture EXACT current output
expect(result).toEqual({
status: 'OK',
data: 'TEST', // Even if this seems wrong!
timestamp: expect.any(Number)
});
});
it('should handle null input as currently implemented', () => {
// Even if it crashes, document it!
expect(() => legacyFunction(null)).toThrow('Cannot read property');
});
});
Golden Master Testing:
# Capture current outputs
for input in test_inputs/*; do
./legacy_app < "$input" > "golden_masters/$(basename $input).output"
done
# After changes, verify outputs match
for input in test_inputs/*; do
./modernized_app < "$input" > temp.output
diff "golden_masters/$(basename $input).output" temp.output
done
Phase 3: ISOLATE (Strangler Fig Pattern)
Wrap Legacy Code:
// Step 1: Create wrapper (Facade)
class ModernInterface {
constructor() {
this.legacy = new LegacySystem();
}
async processData(input) {
// Modern interface
const legacyFormat = this.convertToLegacyFormat(input);
const result = this.legacy.oldProcessMethod(legacyFormat);
return this.convertToModernFormat(result);
}
convertToLegacyFormat(modern) {
// Transform modern input to legacy format
}
convertToModernFormat(legacy) {
// Transform legacy output to modern format
}
}
Phase 4: MODERNIZE (Incremental Updates)
Safe Modernization Patterns:
1. Branch by Abstraction:
class DataProcessor {
constructor(useModern = false) {
this.useModern = useModern;
}
process(data) {
if (this.useModern) {
return this.modernProcess(data);
}
return this.legacyProcess(data);
}
legacyProcess(data) {
// Original implementation
}
modernProcess(data) {
// New implementation
}
}
2. Parallel Run (Verify Compatibility):
async function processWithVerification(data) {
const [legacyResult, modernResult] = await Promise.all([
legacyProcess(data),
modernProcess(data)
]);
// Compare results
if (JSON.stringify(legacyResult) !== JSON.stringify(modernResult)) {
console.error('Results mismatch!', { legacyResult, modernResult });
// Use legacy result for safety
return legacyResult;
}
// Both match, safe to use modern
return modernResult;
}
🔧 Common Modernization Tasks
1. Callback Hell → Promises/Async
Before (Legacy):
getData(function(err, data) {
if (err) return handleError(err);
processData(data, function(err, result) {
if (err) return handleError(err);
saveResult(result, function(err) {
if (err) return handleError(err);
done();
});
});
});
After (Modern):
async function modernFlow() {
try {
const data = await getData();
const result = await processData(data);
await saveResult(result);
done();
} catch (err) {
handleError(err);
}
}
2. Global Variables → Module Pattern
Before (Legacy):
var globalConfig = {};
var globalState = {};
function doSomething() {
globalState.counter++;
return globalConfig.prefix + globalState.counter;
}
After (Modern):
class AppModule {
constructor(config) {
this.config = config;
this.state = { counter: 0 };
}
doSomething() {
this.state.counter++;
return this.config.prefix + this.state.counter;
}
}
export default AppModule;
3. SQL Injection → Parameterized Queries
Before (Legacy - DANGEROUS):
const query = `SELECT * FROM users WHERE id = ${userId}`;
db.query(query);
After (Modern - SAFE):
const query = 'SELECT * FROM users WHERE id = ?';
db.query(query, [userId]);
4. Old Dependencies → Modern Alternatives
// Mapping old to new
const DEPENDENCY_MAP = {
'request': 'axios', // HTTP client
'async': 'native-promises', // Flow control
'underscore': 'lodash', // Utilities
'bower': 'npm', // Package management
'grunt': 'webpack', // Build tool
'jquery': 'vanilla-js', // DOM manipulation
};
// Safe migration approach:
// 1. Install new alongside old
// 2. Migrate one file at a time
// 3. Run tests after each migration
// 4. Remove old when complete
📊 Modernization Checklist
Security Fixes (Priority 1):
- SQL injection vulnerabilities
- XSS vulnerabilities
- Hardcoded secrets removed
- Outdated crypto replaced
- Input validation added
- HTTPS enforcement
Code Quality (Priority 2):
- Global variables eliminated
- Callbacks → Promises/Async
- Var → Let/Const
- == → ===
- Error handling improved
- Dead code removed
Performance (Priority 3):
- Database queries optimized
- Caching implemented
- Lazy loading added
- Bundle size reduced
- Memory leaks fixed
Developer Experience (Priority 4):
- Tests added (>60% coverage)
- Documentation written
- Linting configured
- Types added (TypeScript/JSDoc)
- CI/CD pipeline setup
🚨 Red Flags in Legacy Code
Watch for these danger signs:
// 🚨 Date handling
new Date('2024-01-01') // Timezone issues!
// 🚨 Type coercion
if (value == true) // Use === instead
// 🚨 Eval usage
eval(userInput) // Security nightmare!
// 🚨 Synchronous I/O
const data = fs.readFileSync() // Blocks everything!
// 🚨 Magic numbers
if (status === 2) // What does 2 mean?
// 🚨 No error handling
JSON.parse(data) // Will crash on bad input
💡 Migration Strategies by Language
JavaScript → Modern JS:
# Use automated tools first
npx lebab --transform arrow,let,template legacy.js -o modern.js
npx eslint --fix legacy.js
# TypeScript migration
npx tsc --init
mv legacy.js legacy.ts
npx tsc --allowJs --checkJs
Python 2 → Python 3:
# Automated conversion
2to3 -w legacy.py
# Common fixes
print "Hello" → print("Hello")
xrange() → range()
unicode() → str()
jQuery → Vanilla JS:
// jQuery
$('#element').hide();
$('.class').on('click', handler);
// Vanilla
document.getElementById('element').style.display = 'none';
document.querySelectorAll('.class').forEach(el => {
el.addEventListener('click', handler);
});
📈 Success Metrics
Track modernization progress:
## Legacy Modernization Scorecard
### Week 1 | Week 4 | Week 8
----------|---------|--------
Coverage: 0% | 45% | 78%
Security Issues: 12 | 6 | 1
Tech Debt (hours): 200 | 120 | 40
Build Time: 5min | 3min | 1min
Bundle Size: 2.4MB | 1.2MB | 600KB
Load Time: 4s | 2.5s | 1.2s
🔄 Rollback Strategy
Always have an escape plan:
// Feature flags for safe rollout
if (featureFlags.useModernSystem) {
return modernImplementation();
} else {
return legacyImplementation();
}
// Database migrations with rollback
// up.sql
ALTER TABLE users ADD COLUMN email_verified BOOLEAN DEFAULT false;
// down.sql
ALTER TABLE users DROP COLUMN email_verified;
Remember: Legacy code is not bad code - it's proven code that needs careful evolution! 🏛️→🏢
Recommended Agent Skills
Expand your agent's capabilities with these related and highly-rated skills.
debug-detective
Systematic debugging approach for ANY codebase, ANY language, ANY bug type
tool-discovery
Guide for discovering and using @j0kz MCP tools efficiently through search, filtering, and progressive exploration. Use when exploring available capabilities, finding the right tool for a task, or ...
project-standardization
Guides correct usage of @j0kz/mcp-agents standardization and automation scripts including version.json single source of truth, test count automation, URL casing rules, and critical workflow pattern...
api-integration
Master third-party API integration in ANY language with best practices and patterns
documentation-generation
Documentation generation and maintenance patterns including README structure, CHANGELOG management, API documentation, wiki synchronization, and badge updates. Use when creating package docs, updat...
competitive-ads-extractor
Extracts and analyzes competitor ads from ad libraries (Facebook, LinkedIn, TikTok, Google). Use when researching competitor messaging, creative patterns, campaign strategies, or ad inspiration. Ch...
Didn't find tool you were looking for?