Bỏ qua để đến nội dung

Level: L6 — AI Coding & Vibe Coding (Bài 9/12 theo thứ tự sản xuất — · Đối tượng: Người đã học bài 53-59, đã sửa xong lỗi mất dữ liệu. Bài

Sau bài này, bạn có thể:

  • Giải thích đúng bản chất refactor: thay đổi cấu trúc code, giữ nguyên hành vi — khác hoàn toàn với debug hay thêm tính năng mới.
  • Nhận diện dấu hiệu code “đúng nhưng xấu” (code smell) phổ biến nhất: trùng lặp, đặt tên không rõ nghĩa, 1 khối logic làm quá nhiều việc.
  • Dùng test (đã học bài 61 hoặc viết trước nếu chưa có) làm lưới an toàn khi refactor với Claude Code.
  • Refactor phần code trùng lặp trong dự án tích lũy sau khi đã chạy đúng.

Refactor = giữ nguyên hành vi, cải thiện cấu trúc bên trong. Đây là định nghĩa quan trọng nhất bài này: nếu 1 thay đổi làm sản phẩm hoạt động khác đi (dù là khác tốt hơn), đó không còn là refactor thuần túy — đó là sửa lỗi (bài 59) hoặc thêm tính năng (bài 64). Refactor đúng nghĩa: trước và sau khi refactor, người dùng không nhận ra gì thay đổi — chỉ người đọc code (hoặc AI) mới thấy code rõ ràng hơn, ít trùng lặp hơn, dễ sửa tiếp hơn.

Vì sao code “đúng nhưng xấu” là vấn đề thật: bài 56 đã trích số liệu thật (GitClear 2025): tỷ lệ refactor trong các dự án AI-hỗ trợ đã giảm từ 25% xuống dưới 10% (2021-2024), trong khi trùng lặp code tăng khoảng 4 lần [S97, dẫn lại]. Tốc độ xây dựng nhanh của vibe coding (bài 56) có xu hướng để lại nhiều code trùng lặp/rối hơn nếu không chủ động dành thời gian dọn dẹp — đây chính xác là lý do bài này tồn tại như 1 giai đoạn riêng trong hành trình Level 6, không phải bước “tùy chọn.”

Dấu hiệu code “đúng nhưng xấu” (code smell) phổ biến nhất, dễ nhận ra kể cả khi không đọc được code:

  • Trùng lặp — cùng 1 logic được viết lại ở nhiều chỗ khác nhau (ví dụ: cách kết nối Database được viết riêng lẻ ở cả chức năng thêm và xóa ghi chú, thay vì dùng chung 1 chỗ).
  • Đặt tên không rõ nghĩa — tên biến/hàm không nói lên chức năng thực sự, khiến cả người và AI khó hiểu ý định ban đầu.
  • 1 khối logic làm quá nhiều việc — 1 hàm vừa xử lý dữ liệu, vừa hiển thị giao diện, vừa ghi log — khó sửa 1 phần mà không ảnh hưởng phần khác.

Quy trình chính thức “Refactor code” khi làm việc với Claude Code [S98]:

  1. Xác định code cũ cần refactor — ví dụ nguyên văn: “find deprecated API usage in our codebase” (áp dụng tương tự cho việc tìm trùng lặp/code rối).
  2. Xin đề xuất refactor — ví dụ: “suggest how to refactor… to use modern JavaScript features.”
  3. Áp dụng thay đổi an toàn, nhấn mạnh giữ nguyên hành vi — ví dụ nguyên văn: “refactor… while maintaining the same behavior.”
  4. Chạy lại test để xác minh — ví dụ: “run tests for the refactored code.”

Nguồn chính thức nhấn mạnh 1 nguyên tắc an toàn quan trọng: làm refactor theo từng bước nhỏ, có thể kiểm chứng được (small, testable increments) [S98] — không refactor toàn bộ dự án trong 1 lần.

Code càng trùng lặp/rối, mỗi lần thêm tính năng mới (bài 64) hay sửa lỗi (bài 59) càng tốn công và càng dễ phát sinh lỗi mới. Refactor định kỳ là cách giữ tốc độ xây dựng nhanh (bài 56) không biến thành gánh nặng về sau.

Phân định AI vs con người:

Điều bạn cần hiểu Điều AI có thể thực hiện Điều bạn phải xác nhận
Xác định phạm vi Refactor nhắm vào code smell, không phải hành vi sai Quét code, chỉ ra chỗ trùng lặp/rối Đúng là code đang hoạt động đúng trước khi refactor (nếu đang có lỗi, đó là bài 59 trước)
Đề xuất cách cải thiện Có thể có nhiều cách refactor hợp lý, không chỉ 1 đáp án đúng Đề xuất cách viết lại rõ ràng hơn Cách đề xuất có thực sự dễ hiểu hơn, hay chỉ “khác đi”
Áp dụng Refactor nên làm từng bước nhỏ Viết lại code theo từng bước nhỏ Mỗi bước đã kiểm tra hành vi chưa đổi trước khi sang bước tiếp theo
Xác minh Test là bằng chứng khách quan hành vi không đổi, cảm giác “trông ổn” không đủ Tự chạy lại test sau mỗi bước Toàn bộ test (đã học/viết ở bài 61) vẫn pass — nếu chưa có test, cân nhắc viết trước khi refactor phần quan trọng

Nếu bài 59 là sửa vết rò nước, bài này là lúc bạn sắp xếp lại đường ống nước phía sau tường — nước vẫn chảy đúng như trước (người ở trong nhà không nhận ra gì khác), nhưng đường ống giờ gọn gàng hơn, dễ sửa hơn nếu sau này cần thêm 1 vòi nước mới (tính năng mới, bài 64). Bạn không tự đục tường (đó là việc của thợ xây/AI), nhưng bạn kiểm tra nước vẫn chảy đúng sau khi đường ống được sắp xếp lại.

Áp dụng cho dự án tích lũy: Trợ Lý Ghi Chú Cá Nhân Có AI Tóm Tắt.

Sau bài 59 (sửa lỗi mất dữ liệu) và bài 61 (đã có test cho lưu/đọc ghi chú), giả sử bạn nhận thấy: chức năng thêm, xóa, và đọc ghi chú mỗi cái tự viết lại cách kết nối Database riêng — hoạt động đúng, nhưng trùng lặp ở 3 chỗ.

  1. Đảm bảo có test trước khi refactor — nếu chưa làm bài 61, viết ít nhất 1 integration test cho từng chức năng (thêm/xóa/đọc) trước khi động vào cấu trúc code.
  2. Yêu cầu Claude Code xác định trùng lặp — ví dụ: “tìm phần code trùng lặp giữa 3 chức năng thêm/xóa/đọc ghi chú.”
  3. Xin đề xuất cách gộp lại — ví dụ: “đề xuất cách gộp phần kết nối Database trùng lặp thành 1 chỗ dùng chung, giữ nguyên hành vi hiện tại.”
  4. Áp dụng từng bước nhỏ — gộp lại phần trùng lặp trước, chạy test; nếu pass, mới tiếp tục bước kế tiếp (nếu có).
  5. Chạy lại toàn bộ test sau mỗi bước — không chỉ tin cảm giác “trông có vẻ vẫn chạy”, xác nhận bằng test khách quan.

Vì sao “giữ nguyên hành vi” là ranh giới quan trọng ở đây: nếu trong lúc gộp code kết nối Database, Claude Code “tiện thể” đổi luôn cách xử lý khi xóa 1 ghi chú không tồn tại (ví dụ: từ “báo lỗi” sang “im lặng bỏ qua”) — đây không còn là refactor, đó là 1 thay đổi hành vi cần được nhận biết, xác nhận riêng, và lý tưởng nhất nên tách thành 1 bước khác (gần với debug hoặc cải tiến tính năng), không gộp âm thầm vào refactor.

Khung yêu cầu refactor tái sử dụng:

Tìm phần code trùng lặp/khó bảo trì trong [tên chức năng/module].
Đề xuất cách viết lại rõ ràng hơn, GIỮ NGUYÊN hành vi hiện tại.
Thực hiện theo từng bước nhỏ, chạy test sau mỗi bước.

Checklist trước/sau khi refactor:

[ ] Đã có test cho hành vi hiện tại trước khi bắt đầu chưa?
[ ] Refactor được chia thành từng bước nhỏ, không phải 1 lần lớn?
[ ] Sau mỗi bước, toàn bộ test vẫn pass?
[ ] Không có hành vi nào bị âm thầm thay đổi trong lúc refactor?
Trước (Trùng lặp)Chức năng A -> DBChức năng B -> DBChức năng C -> DBSau (Dùng chung)Chức năng A/B/C vĐường ống dùng chung vDatabase
Hình 6.8 — Refactoring: trước/sau tái cấu trúc, kết quả người dùng không đổi.
  1. Tìm 1 phần code trong dự án của bạn đang hoạt động đúng nhưng trùng lặp hoặc rối (nếu chưa rõ, yêu cầu Claude Code quét giúp).
  2. Đảm bảo có ít nhất 1 test cho phần đó trước khi refactor.
  3. Yêu cầu Claude Code refactor theo khung ở mục 8, theo từng bước nhỏ.
  4. Sau mỗi bước, chạy lại test — dừng ngay nếu có test fail, xác định nguyên nhân trước khi tiếp tục.
  • Refactor khi chưa có test — không có cách khách quan xác nhận hành vi không đổi, chỉ có thể “hy vọng.”
  • Refactor toàn bộ dự án trong 1 lần thay vì từng bước nhỏ — khó xác định bước nào gây ra vấn đề nếu có gì sai.
  • Để AI âm thầm đổi hành vi trong lúc refactor (“tiện thể cải tiến luôn”) — vi phạm chính định nghĩa của refactor, cần tách thành thay đổi riêng, được xác nhận riêng.
  • Refactor chỉ vì “trông đẹp hơn” mà không có lý do thực chất (dễ bảo trì hơn, ít trùng lặp hơn) — tốn thời gian không cần thiết.

13. Giới hạn & khi nào KHÔNG nên áp dụng

Phần tiêu đề “13. Giới hạn & khi nào KHÔNG nên áp dụng”
  • Bài này không dạy cách viết test — xem bài 61 để có đầy đủ khái niệm unit/integration test trước khi refactor phần quan trọng của dự án. Lý do viết bài 60 trước bài 61 (thứ tự sản xuất) nhưng đọc sau (thứ tự Blueprint V1): về mặt thực hành, cần khái niệm test tồn tại trước khi refactor an toàn — nhưng thứ tự đọc chính thức vẫn giữ 60 rồi 61 để khớp Blueprint V1; người đọc theo đúng thứ tự nên lưu ý mục 6 bước 1 (đảm bảo có test) có thể cần đọc trước bài 61 nếu muốn thực hành ngay.
  • Bài này không dạy sửa lỗi (đã học bài 59) — nếu code đang hoạt động sai, quay lại bài 59 trước, không cố “refactor cho hết lỗi.”
  • Không nên refactor phần code sắp bị thay thế hoàn toàn (ví dụ: sắp đổi hẳn cách lưu trữ dữ liệu) — refactor tốn công cho phần sẽ bị bỏ là lãng phí.

Rủi ro lớn nhất của refactor bằng AI là thay đổi hành vi âm thầm mà không ai nhận ra cho tới khi người dùng thật gặp phải — đây là lý do “chạy test sau mỗi bước nhỏ” (mục 4, 6) không phải bước tùy chọn. Số liệu đã trích ở bài 56 (tỷ lệ refactor giảm, trùng lặp code tăng trong các dự án AI-hỗ trợ) cho thấy đây là rủi ro có thật ở quy mô ngành, không chỉ giả định lý thuyết.

  • Luôn có test (hoặc ít nhất xác minh thủ công đáng tin cậy) trước khi refactor phần quan trọng.
  • Refactor theo từng bước nhỏ, kiểm tra sau mỗi bước — dễ lùi lại (dùng Checkpoint đã học bài 57) nếu 1 bước gây vấn đề.
  • Tách bạch rõ ràng: nếu trong lúc refactor bạn muốn đổi thêm hành vi, ghi lại thành việc riêng (debug hoặc tính năng mới), không gộp chung.
16. Nội dung nâng cao (không bắt buộc)

Refactor định kỳ (không chỉ khi code đã quá rối) là thói quen của các đội phát triển phần mềm trưởng thành — dữ liệu GitClear (đã trích bài 56) cho thấy xu hướng ngược lại đang diễn ra khi dùng AI hỗ trợ code (tỷ lệ refactor giảm). Với 1 dự án cá nhân như dự án tích lũy Level 6, dành 1 giai đoạn riêng cho refactor (như bài này) sau vài vòng lặp xây dựng (bài 56) là cách chủ động chống lại đúng xu hướng đó.

  • [S98] Common Workflows, Anthropic — code.claude.com/docs — quy trình chính thức “Refactor code” (xác định → đề xuất → áp dụng an toàn, giữ hành vi → xác minh bằng test), nguyên tắc “small, testable increments.”
  • Dẫn chiếu (không trích dẫn mới): [S97] (số liệu GitClear về refactor/ trùng lặp, đã trích đầy đủ ở bài 56); bài 55 (mô hình 4 lớp); bài 57 (Checkpoint để lùi lại nếu 1 bước refactor gây vấn đề); bài 59 (ranh giới Debug); bài 61 (khái niệm test làm lưới an toàn).

Quy trình chính thức kiểm chứng qua nguồn Tier 1 (S98) ngày 2026-07-12. Định nghĩa refactor và các dấu hiệu code smell là kiến thức chuyên môn phổ quát, không phụ thuộc thời điểm — rủi ro lỗi thời thấp.