Refactor code có hệ thống dựa trên phương pháp luận của Martin Fowler. Sử dụng khi người dùng yêu cầu refactor code, cải thiện cấu trúc code, giảm nợ kỹ thuật, dọn code legacy, loại bỏ code smells, hoặc cải thiện khả năng duy trì code. Skill này hướng dẫn qua cách tiếp theo từng giai đoạn với nghiên cứu, lập kế hoạch, và triển khai tăng dần an toàn.
Một cách tiếp có hệ thống để refactor code dựa trên Refactoring: Improving the Design of Existing Code (ấn bản 2) của Martin Fowler. Skill này nhấn mạnh các thay đổi tăng dần, an toàn được hỗ trợ bởi tests.
"Refactoring là quá trình thay đổi một hệ thống phần mềm theo cách mà nó không làm thay đổi hành vi bên ngoài của code nhưng cải thiện cấu trúc nội bộ của nó." — Martin Fowler
Giai Đoạn 1: Nghiên Cứu & Phân Tích
↓
Giai Đoạn 2: Đánh Giá Phủ Vùng Test
↓
Giai Đoạn 3: Xác Định Code Smell
↓
Giai Đoạn 4: Tạo Kế Hoạch Refactoring
↓
Giai Đoạn 5: Triển Khai Tăng Dần
↓
Giai Đoạn 6: Review & Lặp Lại
Trước khi bắt đầu, làm rõ:
Trình bày phát hiện cho người dùng:
"Refactoring mà không có tests giống như lái xe mà không có thắt dây an toàn." — Martin Fowler
Tests là bật dụng chính của refactoring an toàn. Không có chúng, bạn có nguy cơ giới thiệu bugs.
Kiểm tra các test hiện có
# Tìm các file test
find . -name "*test*" -o -name "*spec*" | head -20
Chạy các test hiện có
# JavaScript/TypeScript
npm test
# Python
pytest -v
# Java
mvn test
Kiểm tra phủ vùng (nếu có)
# JavaScript
npm run test:coverage
# Python
pytest --cov=.
Nếu tests tồn tại và pass:
Nếu tests bị thiếu hoặc không hoàn chỉnh: Trình bày các tùy chọn:
Nếu tests đang fail:
Đối với mỗi hàm được refactor, đảm bảo tests bao phủ:
Sử dụng chu trình "red-green-refactor":
Các triệu chứng của các vấn đề sâu hơn trong code. Chúng không phải là bugs, nhưng là các chỉ báo rằng code có thể được cải thiện.
Xem references/code-smells.md để có danh sách đầy đủ.
| Smell | Dấu Hiệu | Tác Động |
|---|---|---|
| Long Method | Methods > 30-50 dòng | Khó hiểu, test, duy trì |
| Duplicated Code | Cùng logic ở nhiều nơi | Cần sửa lỗi ở nhiều nơi |
| Large Class | Class với quá nhiều trách nhiệm | Vi phạm Single Responsibility |
| Feature Envy | Method sử dụng dữ liệu class khác nhiều | Đóng gói kém |
| Primitive Obsession | Lạm dụng primitives thay vì objects | Thiếu các khái niệm domain |
| Long Parameter List | Methods với 4+ parameters | Khó gọi đúng |
| Data Clumps | Cùng dữ liệu xuất hiện cùng nhau | Thiếu abstraction |
| Switch Statements | Switch/if-else chains phức tạp | Khó mở rộng |
| Speculative Generality | Code "trường hợp" | Độ phức tạp không cần thiết |
| Dead Code | Code không sử dụng | Nhầm lẫn, gánh nặng duy trì |
Phân Tích Tự Động (nếu scripts có sẵn)
python scripts/detect-smells.py <file>
Review Thủ Công
Ưu Tiên Tập trung vào các smells mà:
Trình bày cho người dùng:
Đối với mỗi smell, chọn một refactoring phù hợp từ catalog.
Xem references/refactoring-catalog.md để có danh sách đầy đủ.
| Code Smell | Refactoring Khuyến Nghị |
|---|---|
| Long Method | Extract Method, Replace Temp with Query |
| Duplicated Code | Extract Method, Pull Up Method, Form Template Method |
| Large Class | Extract Class, Extract Subclass |
| Feature Envy | Move Method, Move Field |
| Primitive Obsession | Replace Primitive with Object, Replace Type Code with Class |
| Long Parameter List | Introduce Parameter Object, Preserve Whole Object |
| Data Clumps | Extract Class, Introduce Parameter Object |
| Switch Statements | Replace Conditional with Polymorphism |
| Speculative Generality | Collapse Hierarchy, Inline Class, Remove Dead Code |
| Dead Code | Remove Dead Code |
Sử dụng mẫu tại templates/refactoring-plan.md.
Đối với mỗi refactoring:
QUAN TRỌNG: Introduce refactoring tăng dần theo các giai đoạn.
Giai Đoạn A: Quick Wins (Rủi ro thấp, giá trị cao)
Giai Đoạn B: Cải Tiến Cấu Trúc (Rủi ro trung bình)
Giai Đoạn C: Thay Đổi Kiến Trúc (Rủi ro cao hơn)
Trước khi triển khai:
"Thay Đổi → Test → Xanh? → Commit → Bước tiếp theo"
Đối với mỗi bước refactoring:
Kiểm tra trước
Thực hiện MỘT thay đổi nhỏ
Xác Minh
Nếu tests pass (xanh)
Nếu tests fail (đỏ)
Mỗi commit nên là:
Ví dụ thông điệp commit: