Files
gh-rubencodeforges-codeforg…/skills/refactoring-guide.md
2025-11-30 08:53:15 +08:00

257 lines
5.1 KiB
Markdown

---
name: refactoring-guide
description: 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:**
```javascript
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:**
```javascript
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:**
```python
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:**
```python
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:**
```javascript
if (age >= 18 && age <= 65) {
// eligible
}
```
**After:**
```javascript
const MIN_ELIGIBLE_AGE = 18;
const MAX_ELIGIBLE_AGE = 65;
if (age >= MIN_ELIGIBLE_AGE && age <= MAX_ELIGIBLE_AGE) {
// eligible
}
```
### Introduce Parameter Object
**Before:**
```typescript
function createUser(
name: string,
email: string,
age: number,
address: string,
phone: string
) {
// ...
}
```
**After:**
```typescript
interface UserData {
name: string;
email: string;
age: number;
address: string;
phone: string;
}
function createUser(userData: UserData) {
// ...
}
```
### Replace Magic Number with Named Constant
**Before:**
```go
func calculateDiscount(price float64) float64 {
return price * 0.15
}
```
**After:**
```go
const LOYALTY_DISCOUNT_RATE = 0.15
func calculateDiscount(price float64) float64 {
return price * LOYALTY_DISCOUNT_RATE
}
```
### Decompose Conditional
**Before:**
```javascript
if (date.before(SUMMER_START) || date.after(SUMMER_END)) {
charge = quantity * winterRate + winterServiceCharge;
} else {
charge = quantity * summerRate;
}
```
**After:**
```javascript
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:**
```python
def get_payment(employee):
if employee.is_active:
if employee.has_salary:
return employee.salary
else:
return 0
else:
return 0
```
**After:**
```python
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
1. **Ensure tests exist** (or write them first)
2. **Make small changes** (one refactoring at a time)
3. **Run tests** after each change
4. **Commit frequently** with clear messages
5. **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:
1. Rename unclear variables
2. Extract magic numbers to constants
3. Remove commented-out code
4. Fix inconsistent formatting
5. Add missing error handling
6. Remove unused imports/functions
7. Simplify boolean expressions
These refactorings make code more maintainable and easier to understand.