Quy trình refactoring an toàn — đảm bảo test coverage trước, refactor từng bước nhỏ, verify sau mỗi bước. Bao gồm: strangler fig, extract method, compose method, rename, move patterns.
safety_principles:
1: "NEVER refactor without test coverage"
2: "Small steps — one refactoring at a time"
3: "Verify after EVERY step (compile + test)"
4: "Commit after EVERY successful step"
5: "Rollback immediately if tests break"
6: "Don't mix refactoring with feature changes"
Code smell detected
↓
Test coverage >= 80%? ──NO──→ Write tests FIRST, then refactor
↓ YES
Identify refactoring pattern
↓
Single step possible? ──YES──→ Apply → Verify → Commit
↓ NO
Break into smaller steps
↓
For each step:
1. Apply one change
2. Compile + Lint
3. Run tests
4. If pass → commit
5. If fail → revert immediately
// BEFORE: Long method (40+ lines)
async createOrder(dto: CreateOrderDto) {
// validate stock... (10 lines)
// calculate pricing... (15 lines)
// create record... (10 lines)
// send notification... (5 lines)
}
// AFTER: Extracted methods
async createOrder(dto: CreateOrderDto) {
await this.validateStock(dto.items);
const pricing = this.calculatePricing(dto.items);
const order = await this.saveOrder(dto, pricing);
await this.sendOrderNotification(order);
return order;
}
// BEFORE: Switch/if chains
function calculateDiscount(userType: string, amount: number) {
if (userType === 'premium') return amount * 0.2;
if (userType === 'gold') return amount * 0.15;
return amount * 0.05;
}
// AFTER: Strategy pattern
interface DiscountStrategy {
calculate(amount: number): number;
}
class PremiumDiscount implements DiscountStrategy {
calculate(amount: number) { return amount * 0.2; }
}
strangler_fig:
step_1: "Tạo module mới với interface giống module cũ"
step_2: "Route 10% traffic sang module mới (feature flag)"
step_3: "Monitor errors + performance"
step_4: "Tăng dần: 25% → 50% → 75% → 100%"
step_5: "Remove module cũ khi 100% traffic on new module"
# Step 1: Rename với IDE refactoring tools (update all references)
# Step 2: Verify: grep -r "oldName" src/ → should return 0 results
# Step 3: Compile + Test
# Step 4: Commit: "refactor: rename OldName to NewName"
refactoring_workflow:
1_prepare:
- "Đảm bảo branch riêng (git checkout -b refactor/feature-name)"
- "Check test coverage: npx jest --coverage"
- "Write missing tests nếu coverage < 80%"
- "Commit tests trước khi refactor"
2_identify:
- "Xác định code smell cụ thể"
- "Chọn refactoring pattern phù hợp"
- "Estimate blast radius (Micro/Small/Medium)"
3_execute:
- "Apply ONE refactoring at a time"
- "Compile: npx tsc --noEmit"
- "Test: npx jest"
- "Commit: git commit -m 'refactor: specific change'"
- "Repeat for next refactoring"
4_verify:
- "Run full test suite"
- "Check coverage hasn't decreased"
- "Verify no functional changes (same inputs → same outputs)"
- "Code review by @code-reviewer"
| Anti-pattern | Vấn đề | Fix |
|---|---|---|
| Big bang refactor | Thay đổi quá nhiều cùng lúc | Small steps, commit each |
| Refactor + feature | Mix refactoring với feature code | Separate commits/PRs |
| No tests first | Refactor mà không có test coverage | Write tests TRƯỚC |
| Skip verification | Refactor mà không chạy test | Compile + test EVERY step |
| Premature refactor | Refactor code chỉ dùng 1 lần | "Three strikes then refactor" |
| Rename without grep | Rename nhưng miss references | Use IDE tools + grep verify |