5.1 KiB
5.1 KiB
name, description
| name | description |
|---|---|
| refactoring-guide | Practical refactoring techniques and when to apply them. Auto-loaded when discussing code improvements or refactoring. |
Refactoring Guide
When to Refactor
Red Flags
- Functions longer than 50 lines
- Classes with 10+ methods
- Nested conditionals 3+ levels deep
- Duplicated code in 3+ places
- Complex boolean conditions
- High cyclomatic complexity (>10)
Common Refactorings
Extract Function
Before:
function processOrder(order) {
// Calculate total
let total = 0;
for (let item of order.items) {
total += item.price * item.quantity;
}
// Apply discount
if (order.customer.isPremium) {
total *= 0.9;
}
return total;
}
After:
function processOrder(order) {
const subtotal = calculateSubtotal(order.items);
return applyDiscount(subtotal, order.customer);
}
function calculateSubtotal(items) {
return items.reduce((sum, item) =>
sum + item.price * item.quantity, 0);
}
function applyDiscount(amount, customer) {
return customer.isPremium ? amount * 0.9 : amount;
}
Replace Conditional with Polymorphism
Before:
def calculate_pay(employee):
if employee.type == "manager":
return employee.salary + employee.bonus
elif employee.type == "engineer":
return employee.salary + employee.stock_options
else:
return employee.salary
After:
class Employee:
def calculate_pay(self):
return self.salary
class Manager(Employee):
def calculate_pay(self):
return self.salary + self.bonus
class Engineer(Employee):
def calculate_pay(self):
return self.salary + self.stock_options
Extract Constant
Before:
if (age >= 18 && age <= 65) {
// eligible
}
After:
const MIN_ELIGIBLE_AGE = 18;
const MAX_ELIGIBLE_AGE = 65;
if (age >= MIN_ELIGIBLE_AGE && age <= MAX_ELIGIBLE_AGE) {
// eligible
}
Introduce Parameter Object
Before:
function createUser(
name: string,
email: string,
age: number,
address: string,
phone: string
) {
// ...
}
After:
interface UserData {
name: string;
email: string;
age: number;
address: string;
phone: string;
}
function createUser(userData: UserData) {
// ...
}
Replace Magic Number with Named Constant
Before:
func calculateDiscount(price float64) float64 {
return price * 0.15
}
After:
const LOYALTY_DISCOUNT_RATE = 0.15
func calculateDiscount(price float64) float64 {
return price * LOYALTY_DISCOUNT_RATE
}
Decompose Conditional
Before:
if (date.before(SUMMER_START) || date.after(SUMMER_END)) {
charge = quantity * winterRate + winterServiceCharge;
} else {
charge = quantity * summerRate;
}
After:
if (isWinter(date)) {
charge = winterCharge(quantity);
} else {
charge = summerCharge(quantity);
}
function isWinter(date) {
return date.before(SUMMER_START) || date.after(SUMMER_END);
}
function winterCharge(quantity) {
return quantity * winterRate + winterServiceCharge;
}
function summerCharge(quantity) {
return quantity * summerRate;
}
Replace Nested Conditional with Guard Clauses
Before:
def get_payment(employee):
if employee.is_active:
if employee.has_salary:
return employee.salary
else:
return 0
else:
return 0
After:
def get_payment(employee):
if not employee.is_active:
return 0
if not employee.has_salary:
return 0
return employee.salary
Large-Scale Refactorings
Split Module
When a file is too large (500+ lines), split by responsibility:
user.ts (1000 lines)
↓
user-model.ts (200 lines)
user-service.ts (300 lines)
user-validator.ts (150 lines)
user-utils.ts (100 lines)
Extract Service Layer
Move business logic from controllers:
Before: Controller has 500 lines with business logic
After:
- Controller: 100 lines (request handling)
- Service: 400 lines (business logic)
Introduce Repository
Abstract database access:
Before: Direct SQL/ORM calls throughout code
After: Repository classes handle all data access
Refactoring Workflow
- Ensure tests exist (or write them first)
- Make small changes (one refactoring at a time)
- Run tests after each change
- Commit frequently with clear messages
- Don't mix refactoring with feature work
Red Flags to Watch For
- Premature optimization: Don't refactor for performance without profiling
- Over-engineering: Don't add complexity for theoretical future needs
- Breaking changes: Be careful with public APIs
- Scope creep: Stick to planned refactoring, don't expand mid-work
Quick Wins
Low-hanging fruit for immediate improvement:
- Rename unclear variables
- Extract magic numbers to constants
- Remove commented-out code
- Fix inconsistent formatting
- Add missing error handling
- Remove unused imports/functions
- Simplify boolean expressions
These refactorings make code more maintainable and easier to understand.