Loading...
Loading...
Modernize and improve legacy codebases while maintaining functionality. Use when you need to refactor old code, reduce technical debt, modernize deprecated patterns, or improve code maintainability without breaking existing behavior.
npx skill4agent add aj-geddes/useful-ai-prompts refactor-legacy-code# Review the codebase structure
tree -L 3 -I 'node_modules|dist|build'
# Check for outdated dependencies
npm outdated # or pip list --outdated, composer outdated, etc.
# Identify code complexity hotspots
# Use tools like:
# - SonarQube for code smells
# - eslint for JavaScript
# - pylint for Python
# - RuboCop for Ruby// Add characterization tests to lock in current behavior
describe('LegacyFeature', () => {
it('should preserve existing behavior during refactoring', () => {
// Test current implementation behavior
const input = { /* realistic test data */ };
const result = legacyFunction(input);
// Document expected output
expect(result).toEqual({ /* current actual output */ });
});
});// BEFORE: Long, complex function
function processUserData(user) {
// 50 lines of mixed validation, transformation, and business logic
if (!user.email || !user.email.includes('@')) return null;
const normalized = user.email.toLowerCase().trim();
// ... more complex logic
}
// AFTER: Extracted, focused functions
function validateEmail(email) {
return email && email.includes('@');
}
function normalizeEmail(email) {
return email.toLowerCase().trim();
}
function processUserData(user) {
if (!validateEmail(user.email)) return null;
const email = normalizeEmail(user.email);
// Clear, readable flow
}# BEFORE: Complex conditional logic
def calculate_price(customer_type, base_price):
if customer_type == 'regular':
return base_price
elif customer_type == 'premium':
return base_price * 0.9
elif customer_type == 'vip':
return base_price * 0.8
else:
return base_price
# AFTER: Polymorphic approach
class PricingStrategy:
def calculate(self, base_price):
return base_price
class RegularPricing(PricingStrategy):
pass
class PremiumPricing(PricingStrategy):
def calculate(self, base_price):
return base_price * 0.9
class VIPPricing(PricingStrategy):
def calculate(self, base_price):
return base_price * 0.8
# Usage
pricing = pricing_strategies[customer_type]
price = pricing.calculate(base_price)// BEFORE: Long parameter lists
function createUser(
firstName: string,
lastName: string,
email: string,
phone: string,
address: string,
city: string,
state: string,
zip: string
) {
// ...
}
// AFTER: Parameter object
interface UserData {
firstName: string;
lastName: string;
email: string;
phone: string;
address: Address;
}
interface Address {
street: string;
city: string;
state: string;
zip: string;
}
function createUser(userData: UserData) {
// ...
}// BEFORE: Callback hell
function fetchUserData(userId, callback) {
db.query('SELECT * FROM users WHERE id = ?', [userId], (err, user) => {
if (err) return callback(err);
db.query('SELECT * FROM orders WHERE user_id = ?', [userId], (err, orders) => {
if (err) return callback(err);
callback(null, { user, orders });
});
});
}
// AFTER: Async/await
async function fetchUserData(userId) {
const user = await db.query('SELECT * FROM users WHERE id = ?', [userId]);
const orders = await db.query('SELECT * FROM orders WHERE user_id = ?', [userId]);
return { user, orders };
}// BEFORE: var and string concatenation
var userName = user.firstName + ' ' + user.lastName;
var isActive = user.status === 'active' ? true : false;
// AFTER: const/let and template literals
const userName = `${user.firstName} ${user.lastName}`;
const isActive = user.status === 'active';# BEFORE: Tight coupling to specific implementation
class OrderProcessor:
def __init__(self):
self.db = MySQLDatabase() # Tightly coupled
self.email = SendGridEmail() # Tightly coupled
def process_order(self, order):
self.db.save(order)
self.email.send(order.customer_email, "Order confirmed")
# AFTER: Dependency injection
class OrderProcessor:
def __init__(self, database, email_service):
self.db = database # Any database implementation
self.email = email_service # Any email service
def process_order(self, order):
self.db.save(order)
self.email.send(order.customer_email, "Order confirmed")
# Easy to test with mocks
processor = OrderProcessor(MockDatabase(), MockEmailService())## Refactoring Log
### 2025-01-15: Extract Payment Processing
**Rationale**: Payment logic was embedded in order controller (500 lines)
**Changes**:
- Extracted PaymentService with single responsibility
- Introduced PaymentGateway interface for flexibility
- Added comprehensive unit tests (95% coverage)
**Breaking Changes**: None (internal refactoring only)
**Performance Impact**: 15% improvement in order processing time
### 2025-01-16: Replace Callback with Async/Await
**Rationale**: Callback hell in user authentication flow
**Changes**:
- Converted all authentication methods to async/await
- Simplified error handling with try/catch
- Improved readability (reduced from 150 to 80 lines)
**Breaking Changes**: Function signatures changed (requires updates in calling code)
**Migration**: Updated all 12 call sites in controllers// ❌ Too complex for simple case
class UserNameFormatterFactory {
createFormatter(type) {
return new UserNameFormatter(new FormattingStrategy(type));
}
}
// ✅ Appropriate for simple case
function formatUserName(firstName, lastName) {
return `${firstName} ${lastName}`;
}/** @deprecated Use createUser(userData) instead. Will be removed in v2.0 */
function createUserOld(firstName: string, lastName: string, email: string) {
console.warn('createUserOld is deprecated. Use createUser(userData)');
return createUser({ firstName, lastName, email });
}describe('Refactored User Service', () => {
describe('validateEmail', () => {
it('should accept valid email formats', () => {
expect(validateEmail('user@example.com')).toBe(true);
});
it('should reject invalid email formats', () => {
expect(validateEmail('invalid')).toBe(false);
expect(validateEmail('')).toBe(false);
expect(validateEmail(null)).toBe(false);
});
});
});def test_refactored_order_processing():
"""Ensure refactored code maintains end-to-end behavior"""
# Arrange
order = create_test_order()
processor = OrderProcessor(test_database, test_email_service)
# Act
result = processor.process_order(order)
# Assert
assert result.status == 'completed'
assert test_database.orders.count() == 1
assert test_email_service.sent_count == 1// legacy-user-service.js - 200 lines of complex, coupled code
var UserService = {
createUser: function(fn, ln, em, ph, addr) {
if (!em || em.indexOf('@') === -1) {
return { error: 'Invalid email' };
}
var conn = mysql.createConnection(config);
conn.connect();
conn.query(
'INSERT INTO users (first_name, last_name, email, phone, address) VALUES (?, ?, ?, ?, ?)',
[fn, ln, em.toLowerCase(), ph, addr],
function(err, result) {
if (err) {
console.log(err);
return { error: 'Database error' };
}
// Send welcome email
var nodemailer = require('nodemailer');
var transporter = nodemailer.createTransport(emailConfig);
transporter.sendMail({
to: em,
subject: 'Welcome!',
html: '<h1>Welcome ' + fn + '!</h1>'
}, function(err, info) {
if (err) console.log(err);
});
conn.end();
return { id: result.insertId };
}
);
}
};// user-service.ts - Clean, testable, maintainable
interface UserData {
firstName: string;
lastName: string;
email: string;
phone: string;
address: string;
}
class UserService {
constructor(
private database: Database,
private emailService: EmailService,
private validator: Validator
) {}
async createUser(userData: UserData): Promise<User> {
this.validator.validateEmail(userData.email);
const normalizedData = this.normalizeUserData(userData);
const user = await this.database.users.create(normalizedData);
await this.sendWelcomeEmail(user);
return user;
}
private normalizeUserData(data: UserData): UserData {
return {
...data,
email: data.email.toLowerCase().trim()
};
}
private async sendWelcomeEmail(user: User): Promise<void> {
await this.emailService.send({
to: user.email,
subject: 'Welcome!',
template: 'welcome',
data: { firstName: user.firstName }
});
}
}
// validator.ts
class Validator {
validateEmail(email: string): void {
if (!email || !email.includes('@')) {
throw new ValidationError('Invalid email format');
}
}
}
// Easy to test
describe('UserService', () => {
it('should create user with valid data', async () => {
const mockDb = createMockDatabase();
const mockEmail = createMockEmailService();
const service = new UserService(mockDb, mockEmail, new Validator());
const user = await service.createUser({
firstName: 'John',
lastName: 'Doe',
email: 'john@example.com',
phone: '555-0123',
address: '123 Main St'
});
expect(user.id).toBeDefined();
expect(mockDb.users.create).toHaveBeenCalled();
expect(mockEmail.send).toHaveBeenCalledWith(
expect.objectContaining({ to: 'john@example.com' })
);
});
});