**Description**: Systematically improve code structure and quality while preserving behavior
Refactors code to improve structure and quality while preserving behavior through systematic techniques.
/plugin marketplace add samuelgarrett/claude-code-plugin-test/plugin install core-skills@claude-skills-marketplaceDescription: Systematically improve code structure and quality while preserving behavior
Refactoring is the disciplined technique of restructuring existing code without changing its external behavior. You improve code quality incrementally, safely, and confidently.
🔐 Preserve Behavior: Refactoring must not change what the code does - only how it does it.
1. ✅ Ensure tests pass before refactoring
2. 🔄 Make small, incremental changes
3. ✅ Run tests after each change
4. 💾 Commit after each successful refactor
5. 🔄 Repeat
// ❌ Bad: Duplicated logic
function calculateOrderTotal(order) {
let total = 0;
for (const item of order.items) {
total += item.price * item.quantity;
}
total = total * 1.1; // Tax
return total;
}
function calculateCartTotal(cart) {
let total = 0;
for (const item of cart.items) {
total += item.price * item.quantity;
}
total = total * 1.1; // Tax
return total;
}
// ✅ Good: Extracted common logic
function calculateItemsSubtotal(items) {
return items.reduce((sum, item) => sum + item.price * item.quantity, 0);
}
function applyTax(amount) {
return amount * 1.1;
}
function calculateOrderTotal(order) {
return applyTax(calculateItemsSubtotal(order.items));
}
function calculateCartTotal(cart) {
return applyTax(calculateItemsSubtotal(cart.items));
}
// ❌ Bad: 100-line method doing everything
function processUserRegistration(userData) {
// Validate
if (!userData.email) throw new Error('Email required');
if (!userData.email.includes('@')) throw new Error('Invalid email');
if (!userData.password) throw new Error('Password required');
if (userData.password.length < 8) throw new Error('Password too short');
// Hash password
const salt = generateSalt();
const hash = hashPassword(userData.password, salt);
// Create user
const user = {
id: generateId(),
email: userData.email.toLowerCase(),
passwordHash: hash,
createdAt: new Date()
};
// Save to database
database.users.insert(user);
// Send welcome email
emailService.send({
to: user.email,
template: 'welcome',
data: { name: userData.name }
});
// Log analytics
analytics.track('user_registered', { userId: user.id });
return user;
}
// ✅ Good: Broken into focused functions
function processUserRegistration(userData) {
const validatedData = validateUserData(userData);
const user = createUser(validatedData);
await saveUser(user);
await sendWelcomeEmail(user);
trackRegistration(user);
return user;
}
function validateUserData(userData) {
validateEmail(userData.email);
validatePassword(userData.password);
return userData;
}
function createUser(userData) {
return {
id: generateId(),
email: userData.email.toLowerCase(),
passwordHash: hashUserPassword(userData.password),
createdAt: new Date()
};
}
// ... other focused functions
// ❌ Bad: Class doing too much
class UserManager {
createUser() { }
deleteUser() { }
validateEmail() { }
hashPassword() { }
sendEmail() { }
logAnalytics() { }
generateReport() { }
exportToCSV() { }
}
// ✅ Good: Single Responsibility Principle
class UserService {
createUser() { }
deleteUser() { }
}
class UserValidator {
validateEmail() { }
validatePassword() { }
}
class AuthService {
hashPassword() { }
verifyPassword() { }
}
class EmailService {
sendEmail() { }
}
class AnalyticsService {
logEvent() { }
}
class ReportService {
generateReport() { }
exportToCSV() { }
}
// ❌ Bad: Too many parameters
function createUser(
email,
password,
firstName,
lastName,
age,
country,
city,
zipCode,
preferences
) {
// ...
}
// ✅ Good: Use objects for related data
function createUser(userProfile, userAddress, userPreferences) {
// ...
}
// Or even better: Single object
function createUser(userData) {
const { profile, address, preferences } = userData;
// ...
}
// ❌ Bad: Using primitives for domain concepts
function processPayment(amount: number, currency: string, userId: string) {
// What if currency is 'abc'? What if userId is not a valid ID?
}
// ✅ Good: Use value objects
class Money {
constructor(
readonly amount: number,
readonly currency: Currency
) {}
}
class UserId {
constructor(readonly value: string) {
if (!this.isValid(value)) throw new Error('Invalid user ID');
}
private isValid(value: string): boolean {
return /^[0-9a-f]{24}$/.test(value);
}
}
function processPayment(amount: Money, userId: UserId) {
// Type-safe and validated
}
// ❌ Bad: Nested conditionals
function processOrder(order) {
if (order) {
if (order.items && order.items.length > 0) {
if (order.user) {
if (order.user.paymentMethod) {
// Process order
} else {
throw new Error('No payment method');
}
} else {
throw new Error('No user');
}
} else {
throw new Error('Empty order');
}
} else {
throw new Error('No order');
}
}
// ✅ Good: Guard clauses
function processOrder(order) {
if (!order) throw new Error('No order');
if (!order.items || order.items.length === 0) throw new Error('Empty order');
if (!order.user) throw new Error('No user');
if (!order.user.paymentMethod) throw new Error('No payment method');
// Process order (now at top level)
return processPayment(order);
}
// ❌ Bad
if (user.status === 2) {
setTimeout(retry, 3000);
}
// ✅ Good
const UserStatus = {
ACTIVE: 1,
SUSPENDED: 2,
DELETED: 3
};
const RETRY_DELAY_MS = 3000;
if (user.status === UserStatus.SUSPENDED) {
setTimeout(retry, RETRY_DELAY_MS);
}
// Before
function printOwing(invoice) {
let outstanding = 0;
console.log('***********************');
console.log('**** Customer Owes ****');
console.log('***********************');
for (const order of invoice.orders) {
outstanding += order.amount;
}
console.log(`name: ${invoice.customer}`);
console.log(`amount: ${outstanding}`);
}
// After
function printOwing(invoice) {
printBanner();
const outstanding = calculateOutstanding(invoice);
printDetails(invoice, outstanding);
}
function printBanner() {
console.log('***********************');
console.log('**** Customer Owes ****');
console.log('***********************');
}
function calculateOutstanding(invoice) {
return invoice.orders.reduce((sum, order) => sum + order.amount, 0);
}
function printDetails(invoice, outstanding) {
console.log(`name: ${invoice.customer}`);
console.log(`amount: ${outstanding}`);
}
// Before
function calc(d) {
return d * 0.1;
}
// After
function calculateTax(amount) {
const TAX_RATE = 0.1;
return amount * TAX_RATE;
}
// Before
function getSpeed(bird) {
switch (bird.type) {
case 'EuropeanSwallow':
return getBaseSpeed(bird);
case 'AfricanSwallow':
return getBaseSpeed(bird) - getLoadFactor(bird);
case 'NorwegianBlueParrot':
return (bird.isNailed) ? 0 : getBaseSpeed(bird);
default:
throw new Error('Unknown bird');
}
}
// After
class Bird {
getSpeed() {
throw new Error('Must implement getSpeed');
}
}
class EuropeanSwallow extends Bird {
getSpeed() {
return this.getBaseSpeed();
}
}
class AfricanSwallow extends Bird {
getSpeed() {
return this.getBaseSpeed() - this.getLoadFactor();
}
}
class NorwegianBlueParrot extends Bird {
getSpeed() {
return this.isNailed ? 0 : this.getBaseSpeed();
}
}
// Before
function getPrice(quantity, itemPrice) {
const basePrice = quantity * itemPrice;
const discountFactor = 0.98;
if (basePrice > 1000) {
discountFactor = 0.95;
}
return basePrice * discountFactor;
}
// After
function getPrice(quantity, itemPrice) {
return getBasePrice(quantity, itemPrice) * getDiscountFactor(quantity, itemPrice);
}
function getBasePrice(quantity, itemPrice) {
return quantity * itemPrice;
}
function getDiscountFactor(quantity, itemPrice) {
return getBasePrice(quantity, itemPrice) > 1000 ? 0.95 : 0.98;
}
// Before
function drawRectangle(x, y, width, height, color, borderWidth, borderColor) {
// ...
}
// After
class Rectangle {
constructor(position, dimensions, style) {
this.position = position; // { x, y }
this.dimensions = dimensions; // { width, height }
this.style = style; // { color, borderWidth, borderColor }
}
}
function drawRectangle(rectangle) {
// ...
}
1. [ ] Identify code smell or improvement opportunity
2. [ ] Ensure all tests pass (baseline)
3. [ ] Make one small refactoring change
4. [ ] Run tests - verify still passing
5. [ ] Commit with descriptive message
6. [ ] Repeat
Feature: Refactor user authentication code
[ ] Review current implementation
[ ] Ensure all tests pass
[ ] Extract validation logic → separate function
[ ] Run tests ✓
[ ] Commit "Extract email validation"
[ ] Extract password hashing → separate function
[ ] Run tests ✓
[ ] Commit "Extract password hashing"
[ ] Replace conditional with strategy pattern
[ ] Run tests ✓
[ ] Commit "Introduce authentication strategy pattern"
[ ] Add missing tests for edge cases
[ ] Run tests ✓
[ ] Commit "Add tests for auth edge cases"
[ ] Final review and cleanup
High Test Coverage → Refactor Fearlessly
Low Test Coverage → Write Tests First, Then Refactor
No Tests → Add Tests, Then Refactor Carefully
For large legacy systems:
1. Identify a piece of functionality to refactor
2. Create new implementation alongside old
3. Redirect calls to new implementation
4. Once stable, remove old implementation
5. Repeat for next piece
This allows incremental refactoring of large systems
1. Create abstraction interface
2. Implement interface with old code
3. Replace direct calls with abstraction calls
4. Create new implementation of interface
5. Switch to new implementation
6. Remove old implementation
Remember: Refactoring is not rewriting. It's disciplined improvement in small, safe steps. Leave the codebase better than you found it - the Boy Scout Rule!