Review code AI-generated bằng con mắt bạn dùng để review code người viết là cách nhanh nhất để một lỗi tinh vi lọt thẳng vào production.
Vì Sao Code AI-Generated Cần Một Lăng Kính Review Khác
Khi review code do đồng nghiệp viết, bạn ngầm dựa vào một số giả định: người viết đã tư duy qua vấn đề, đã cân nhắc trade-off, và các lỗi thường là lỗi "con người" quen thuộc — quên edge case, gõ nhầm biến, thiếu null check. Reviewer dày dạn kinh nghiệm biết cách soi vào những điểm mù quen thuộc này.
AI-generated code phá vỡ những giả định đó. Lỗi của AI không phải lỗi "con người" — chúng có pattern hoàn toàn khác. AI hiếm khi gõ nhầm biến, nhưng nó có thể hallucinate cả một API. AI hiếm khi quên comment, nhưng comment của nó có thể mô tả sai logic thực tế. AI thường viết code "trông rất đầy đủ" — có try/catch, có validation, có comment giải thích — nhưng độ đầy đủ về hình thức không đảm bảo độ đúng về logic. Đây là hiện tượng gọi là "plausible wrongness" (sai một cách hợp lý) — code sai nhưng theo cách khiến nó trông giống code đúng hơn bình thường.
Thêm vào đó, AI-generated code thường không có "dấu vết tư duy". Khi đồng nghiệp viết code, PR description và commit history thường phản ánh quá trình suy nghĩ — tại sao chọn cách này, đã thử cách khác chưa. Code AI-generated, nếu không có sự chủ động của người dùng, thường thiếu ngữ cảnh này hoàn toàn.
Vì vậy, review AI-generated code đòi hỏi bạn chuyển từ "tìm lỗi con người quen thuộc" sang "verify từng claim mà code đưa ra" — coi mỗi function call, mỗi comment, mỗi nhánh xử lý là một khẳng định cần được kiểm chứng độc lập, không phải một sự thật mặc định.
Mẹo: Trước khi bắt đầu review, tự nhắc mình: "Đoạn code này có thể sai theo những cách mà code người viết thường không sai." Điều này giúp bạn tránh áp dụng máy móc checklist review cũ.
Checklist Review Có Cấu Trúc
Một checklist có hệ thống giúp bạn không bỏ sót các nhóm lỗi quan trọng, đặc biệt khi review dưới áp lực thời gian. Dưới đây là checklist được thiết kế riêng cho AI-generated code, chia theo lớp kiểm tra:
Lớp 1 — Tồn tại và chính xác (Existence & Accuracy):
- Mọi API, method, package được gọi có thực sự tồn tại và đúng version không?
- Import có trỏ đúng module thật trong project không (không phải path tưởng tượng)?
- Comment có mô tả đúng những gì code thực sự làm không (không phải những gì AI "nghĩ" nó làm)?
Lớp 2 — Logic nghiệp vụ (Business Logic):
- Logic có khớp với spec/yêu cầu ban đầu không, hay AI đã "tự bổ sung" thêm rule?
- Các nhánh điều kiện có cover đúng các case trong spec không, có case nào bị bỏ sót?
- Số liệu, ngưỡng, hằng số trong code có nguồn gốc rõ ràng không, hay là "magic number" bịa ra?
Lớp 3 — Điều kiện biên (Boundary Conditions):
- Input rỗng, null, undefined được xử lý thế nào?
- Giá trị biên (0, âm, rất lớn, chuỗi rỗng) được xử lý đúng chưa?
- Concurrent access / race condition có được cân nhắc không (nếu liên quan)?
Lớp 4 — Bảo mật (Security):
- Input từ người dùng có được validate/sanitize trước khi dùng không?
- Có injection risk (SQL, command, template) không?
- Có lộ thông tin nhạy cảm trong log, error message, hay response không?
- Authorization check có đúng và đủ không (không chỉ authentication)?
Lớp 5 — Test và khả năng verify (Testability):
- Test đi kèm (nếu có) có thực sự test đúng behavior quan trọng, hay chỉ test "cho có"?
- Test có cover được edge case chính không, hay chỉ cover happy path?
Lớp 6 — Tác động hệ thống (System Impact):
- Thay đổi này có phá vỡ contract mà phần khác của hệ thống đang phụ thuộc không?
- Performance có bị ảnh hưởng đáng kể không (N+1 query, vòng lặp không cần thiết)?
Mẹo: In checklist này ra hoặc lưu làm snippet có thể paste nhanh vào mỗi PR description khi review code AI-generated — việc có checklist vật lý trước mắt giảm đáng kể tỷ lệ bỏ sót so với việc chỉ "nhớ trong đầu".
Dùng AI Như Một Trợ Lý Review
Một nghịch lý thú vị: công cụ tạo ra vấn đề cũng có thể là công cụ giúp bạn phát hiện vấn đề — miễn là bạn dùng đúng cách, với đúng mức độ hoài nghi.
Dùng một session/model khác để review, không phải session đã viết code. Nếu code được generate bởi session A, đừng hỏi chính session A "code này có đúng không" — nó có xu hướng bảo vệ output trước đó của mình. Mở session mới hoặc dùng model khác, cung cấp code và spec, hỏi độc lập.
Ví dụ prompt review:
Đây là spec: [dán spec gốc]
Đây là code implementation: [dán code]
Nhiệm vụ của bạn là review độc lập, đóng vai một senior engineer khó tính:
1. Liệt kê mọi điểm code không khớp với spec.
2. Liệt kê mọi API/method được gọi mà bạn không chắc chắn tồn tại.
3. Liệt kê edge case mà code có thể xử lý sai (null, rỗng, giá trị biên, concurrent).
4. Liệt kê rủi ro bảo mật nếu có.
Không cần khen phần đúng, chỉ tập trung liệt kê vấn đề tiềm ẩn.
Yêu cầu AI đóng vai "kẻ phá hoại" (adversarial reviewer). Prompt dạng "Giả sử bạn muốn tìm cách khiến đoạn code này fail hoặc bị exploit — bạn sẽ làm gì?" thường moi ra nhiều edge case hơn là hỏi "code này có đúng không?"
Dùng AI để generate test case dựa trên spec, độc lập với code. Sau đó chạy test đó lên code — cách này giảm thiểu tình trạng "test được viết ra để khớp với code thay vì khớp với spec".
Luôn coi output review của AI là gợi ý cần verify, không phải phán quyết cuối cùng. AI review có thể bỏ sót vấn đề thật hoặc report vấn đề không có thật (false positive) — bạn vẫn là người quyết định cuối cùng.
Mẹo: Kỹ thuật hiệu quả nhất là "cross-model review" — nếu có quyền truy cập nhiều model khác nhau, dùng một model khác hẳn (không cùng nhà cung cấp) với model đã generate code để review. Sự khác biệt trong cách huấn luyện giúp bắt được nhiều loại lỗi khác nhau.
Review Cho "Plausible Wrongness"
Đây là kỹ năng khó nhất và quan trọng nhất khi review AI-generated code: học cách nhận diện code "sai một cách hợp lý" — code có vẻ ngoài hoàn toàn đúng đắn (structure gọn, comment rõ, naming chuẩn) nhưng logic bên trong sai.
Dấu hiệu nhận biết plausible wrongness:
Comment mô tả một hành vi lý tưởng, không phải hành vi thực tế của code. Ví dụ comment ghi // handles all edge cases including empty array nhưng code thực tế không hề check mảng rỗng. AI thường sinh comment dựa trên "ý định" thay vì verify thực tế code làm được điều đó.
Try/catch bắt lỗi nhưng xử lý sai hoặc nuốt lỗi im lặng. Code có vẻ "an toàn" vì có error handling, nhưng catch block chỉ log rồi bỏ qua, khiến lỗi thực sự bị che giấu thay vì được xử lý đúng.
Tên biến/hàm rất mô tả nhưng logic bên trong không khớp tên. Ví dụ hàm tên validateEmail nhưng chỉ check chuỗi có chứa ký tự @, không thực sự validate format email đầy đủ như tên gợi ý.
Logic "đối xứng giả" — code xử lý case A và case B trông có vẻ song song, đối xứng, nhưng thực tế một nhánh có bug tinh vi mà mắt thường lướt qua sẽ bỏ lỡ vì nó "trông giống" nhánh kia.
Số liệu/ngưỡng có vẻ có cơ sở kỹ thuật nhưng thực chất bịa. Ví dụ "retry tối đa 3 lần vì đây là best practice" — nghe hợp lý nhưng không có nguồn cụ thể, có thể không phù hợp với context thực tế của bạn.
Kỹ thuật để bắt plausible wrongness: đọc code với câu hỏi "nếu tôi cố tình muốn phá vỡ đoạn code này, tôi sẽ tấn công vào đâu?" thay vì "code này có vẻ ổn không?". Tư duy đối kháng (adversarial thinking) hiệu quả hơn nhiều so với đọc xuôi để tìm sự thoải mái.
Mẹo: Đọc mọi comment trong code AI-generated với thái độ hoài nghi ngang với đọc chính logic — coi comment như một "claim" cần verify đối chiếu với code thật, không phải một chú thích đáng tin sẵn.
Dùng Diffing Tool và Test Như Công Cụ Hỗ Trợ Review
Công cụ diff và test không chỉ để "xem đã thay đổi gì" — chúng là công cụ chủ động giúp thu hẹp phạm vi cần soi kỹ.
Diff theo từng semantic chunk, không đọc toàn bộ file lại từ đầu. Dùng git diff hoặc tool review có side-by-side view để tập trung vào chính xác phần thay đổi — nhưng đồng thời luôn mở rộng context xung quanh diff (ít nhất 10-15 dòng trên dưới) để hiểu tác động.
Đặc biệt chú ý tới các diff "nhỏ nhưng nguy hiểm". Một thay đổi từ === sang ==, từ && sang ||, từ < sang <= — những thay đổi 1 ký tự này rất dễ bị lướt qua trong diff nhưng có thể đổi hoàn toàn logic.
Chạy test suite hiện có trước, rồi mới đọc code mới. Nếu test pass nhưng bạn nghi ngờ, đó là tín hiệu test suite có thể chưa đủ cover — không phải bằng chứng code đúng.
Viết test mới dựa trên spec, không dựa trên code. Đây là kỹ thuật quan trọng nhất: nếu bạn viết test case dựa trên đọc code, bạn có nguy cơ vô tình "test theo cách code đã làm" thay vì "test theo cách nó nên làm". Luôn quay lại spec gốc khi viết test review.
Dùng mutation testing (kiểm thử đột biến — cố tình sửa nhỏ logic để xem test có bắt được không) hoặc test coverage tool để tìm chỗ code không được test cover. Những dòng code không có test nào chạy qua là nơi rủi ro plausible wrongness cao nhất.
So sánh diff với mô tả PR/commit message. Nếu PR nói "chỉ sửa bug validate email" nhưng diff có thay đổi ở file xử lý payment, đó là cờ đỏ cần hỏi ngay.
Mẹo: Trước khi đọc code diff, tự viết ra (hoặc nhắc lại trong đầu) 3 test case bạn kỳ vọng phải pass dựa trên spec — sau đó mới đọc code để xem nó có thực sự handle đúng 3 case đó không. Cách này giữ bạn bám vào spec thay vì bị code "dẫn dắt" tư duy.
Review Nên Kéo Dài Bao Lâu và "Xong" Nghĩa Là Gì
Một câu hỏi thực tế nhiều engineer gặp phải: dành bao nhiêu thời gian là đủ cho một review AI-generated code, và làm sao biết mình đã review "xong"?
Thời gian không nên tỷ lệ nghịch với tốc độ AI generate code. Đây là sai lầm phổ biến nhất: vì AI viết code trong 30 giây, người review cũng có xu hướng chỉ dành 30 giây để đọc. Thời gian review nên tỷ lệ với độ phức tạp và rủi ro của thay đổi, không phải tốc độ tạo ra nó.
Hướng dẫn thực tế theo mức độ rủi ro:
- Thay đổi nhỏ, rủi ro thấp (sửa lỗi chính tả, đổi tên biến, format code): review nhanh, tập trung xác nhận không có side effect ngoài ý muốn.
- Thay đổi vừa, logic mới nhưng phạm vi hẹp (thêm một validation, một helper function độc lập): áp dụng đầy đủ checklist 6 lớp ở phần trên, thời gian tỷ lệ với số nhánh logic.
- Thay đổi lớn, ảnh hưởng business logic hoặc bảo mật (tính phí, xử lý payment, authorization): cần review kỹ ở mức tối đa — bao gồm chạy thử thủ công, viết test bổ sung, và có thể cần second reviewer.
"Xong" không có nghĩa là "đọc hết mọi dòng" — mà có nghĩa là bạn đã trả lời được với sự tự tin hợp lý cho các câu hỏi: Logic có khớp spec? Edge case quan trọng đã được xử lý? Không có hallucination về API? Không có rủi ro bảo mật rõ ràng? Bạn có thể giải thích đoạn code này cho người khác?
Nếu bạn không thể trả lời "có" cho tất cả các câu hỏi trên với sự tự tin thật sự (không phải "chắc là ổn"), review chưa xong — dù bạn đã đọc hết từng dòng code.
Mẹo: Đặt quy tắc thời gian tối thiểu (không phải tối đa) cho review AI-generated code liên quan tới logic nghiệp vụ quan trọng — ví dụ "không dưới 10 phút cho mọi PR chạm vào luồng thanh toán", để tránh xu hướng review nhanh hời hợt chỉ vì code do AI viết.
Thực Hành: Chạy Full Review Trên Code AI-Generated
Bước 1 — Chuẩn bị một task thực tế và spec rõ ràng. Ví dụ: "Viết API endpoint POST /api/coupons/apply nhận mã giảm giá và order total, trả về giá sau giảm. Coupon có thể là percentage (tối đa 50%) hoặc fixed amount (không vượt quá order total). Coupon hết hạn hoặc không tồn tại trả về lỗi 400."
Bước 2 — Yêu cầu AI generate implementation đầy đủ kèm test.
Bước 3 — Chạy Lớp 1 của checklist: verify tồn tại. Kiểm tra mọi import, mọi API framework được gọi (ví dụ ORM query method) có đúng thật không.
Bước 4 — Chạy Lớp 2 và 3: đối chiếu logic với spec, liệt kê boundary case. Tự viết ra danh sách: coupon percentage đúng 50%? Order total bằng 0? Fixed amount coupon lớn hơn order total (đã được clamp chưa)? Coupon hết hạn đúng lúc nửa đêm?
Bước 5 — Chạy Lớp 4: kiểm tra bảo mật. Coupon code có được validate tránh injection không? Có rate-limit để tránh brute-force mã coupon không?
Bước 6 — Dùng AI session khác làm adversarial reviewer với prompt đã nêu ở phần "Dùng AI như trợ lý review" — so sánh kết quả với checklist bạn tự chạy.
Bước 7 — Viết bổ sung ít nhất 3 test case cho boundary condition chưa được cover, chạy thử để xác nhận code pass hoặc lộ ra bug.
Bước 8 — Ra quyết định merge/reject/sửa dựa trên toàn bộ bằng chứng thu thập được, và ghi chú ngắn gọn lý do vào PR description.
Thực hành đầy đủ 8 bước này một vài lần sẽ giúp bạn nội hóa quy trình — sau đó bạn có thể rút gọn tùy theo mức độ rủi ro thực tế của từng task, như đã bàn ở phần trước.
Mẹo: Lưu lại prompt adversarial reviewer ở bước 6 thành một snippet có thể tái sử dụng — đây là công cụ bạn sẽ dùng lặp đi lặp lại cho mọi PR quan trọng.
Những điểm chính
- Code AI-generated cần lăng kính review khác với code người viết — lỗi của nó có pattern riêng, đặc biệt là "plausible wrongness": sai nhưng trông rất hợp lý.
- Dùng checklist có cấu trúc theo 6 lớp: tồn tại/chính xác, logic nghiệp vụ, điều kiện biên, bảo mật, khả năng test, và tác động hệ thống.
- AI có thể là trợ lý review hiệu quả nếu dùng đúng cách: session độc lập, đóng vai adversarial reviewer, generate test từ spec — nhưng luôn verify output của nó, không nhận làm phán quyết cuối.
- Đọc comment với thái độ hoài nghi ngang code — comment có thể mô tả "ý định" thay vì hành vi thực tế.
- Dùng diff và test một cách chủ động: viết test từ spec (không từ code), chú ý các thay đổi nhỏ nhưng nguy hiểm, dùng coverage để tìm điểm mù.
- Thời gian review nên tỷ lệ với rủi ro và độ phức tạp của thay đổi, không tỷ lệ với tốc độ AI tạo ra nó. "Xong" nghĩa là tự tin trả lời được các câu hỏi cốt lõi, không phải đọc hết từng dòng.