- Trong môi trường phát triển hợp tác cùng AI, con người phải xác định rõ định hướng và các quyết định của dự án thì mới có thể duy trì chất lượng
- Cần tài liệu hóa chính xác để cả AI lẫn các nhà phát triển khác đều hiểu rõ yêu cầu và các ràng buộc
- Xây dựng hệ thống debug và quy trình code review để tăng cường độ tin cậy và quy trình kiểm chứng đối với mã do AI tạo ra
- Đảm bảo tính ổn định và nhất quán của mã bằng cách đánh dấu các hàm có rủi ro bảo mật, tách biệt test và áp dụng quy tắc lint nghiêm ngặt
- Duy trì khả năng kiểm soát việc sinh mã bằng AI và tối đa hóa hiệu quả thông qua chia nhỏ đơn vị công việc và giảm thiểu độ phức tạp
1. Thiết lập tầm nhìn rõ ràng
- Con người hiểu thế giới, đội ngũ và hành vi người dùng, nhưng AI không có kinh nghiệm nên cần chỉ dẫn một cách tường minh
- Trong dự án, những quyết định không được tài liệu hóa sẽ bị AI tự đưa ra thay
- Cần thảo luận trước về kiến trúc, giao diện, cấu trúc dữ liệu, thuật toán và xác định cách kiểm thử
- Những quyết định dài hạn và khó thay đổi bắt buộc phải do con người trực tiếp quản lý
2. Duy trì tài liệu chính xác
- Để AI tạo ra mã phù hợp với mục tiêu, việc truyền đạt yêu cầu chi tiết là điều thiết yếu
- Vì các nhà phát triển khác cũng phải cung cấp cùng một thông tin cho AI, cần đưa tài liệu theo định dạng chuẩn hóa vào kho mã nguồn
- Ghi chép chi tiết về yêu cầu, ràng buộc, kiến trúc, tiêu chuẩn coding, design pattern, v.v.
- Sử dụng sơ đồ UML, flowchart, pseudocode để biểu diễn trực quan các cấu trúc phức tạp
3. Xây dựng hệ thống debug hỗ trợ AI
- Cần chuẩn bị hệ thống debug hiệu quả để AI có thể nhanh chóng kiểm chứng chức năng của mã
- Ví dụ: thu thập log của mọi node trong hệ thống phân tán và cung cấp thông tin tóm tắt như “dữ liệu đã được gửi tới tất cả các node”
- Nhờ đó có thể giảm chi phí chạy lệnh và tăng tốc độ xác định vấn đề
4. Đánh dấu mức độ review mã
- Cần phân chia cường độ review theo mức độ quan trọng của mã
- Ví dụ: thêm chú thích
//A sau hàm do AI viết để biểu thị đã được con người xem xét hay chưa
- Cơ chế này giúp nhận diện và quản lý mã chưa được kiểm tra dễ dàng hơn
5. Viết đặc tả ở mức cao và tự kiểm thử trực tiếp
- AI có thể lách bằng mock object hoặc giá trị hardcode để vượt qua test
- Để ngăn điều này, cần tự viết kiểm thử dựa trên thuộc tính (property-based testing)
- Ví dụ: khởi động lại server và kiểm tra tính nhất quán của giá trị trong cơ sở dữ liệu
- Mã test cần được tách sang khu vực riêng để AI không thể sửa đổi
6. Tách biệt kiểm thử giao diện
- Cần để AI viết kiểm thử giao diện mà không biết ngữ cảnh của phần mã khác
- Nhờ không bị ảnh hưởng bởi AI triển khai, tính khách quan của bài test được giữ nguyên
- Các bài test này cũng phải được bảo vệ để AI không thể tùy ý chỉnh sửa
7. Quy tắc lint và formatting nghiêm ngặt
- Code style nhất quán và quy tắc lint là yếu tố thiết yếu để duy trì chất lượng và phát hiện lỗi sớm
- Cả AI và con người đều có thể dễ dàng kiểm tra chất lượng mã
8. Tận dụng prompt cho code agent theo từng ngữ cảnh
- Dùng các tệp prompt theo từng dự án như CLAUDE.md để giảm chi phí hiểu ban đầu của AI
- Bao gồm tiêu chuẩn coding, design pattern, yêu cầu, v.v. để nâng cao chất lượng và hiệu quả sinh mã của AI
9. Nhận diện và đánh dấu các hàm có rủi ro bảo mật
- Cần đánh dấu rõ ràng các hàm nhạy cảm về bảo mật như xác thực, phân quyền, xử lý dữ liệu
- Ví dụ: dùng chú thích
//HIGH-RISK-UNREVIEWED, //HIGH-RISK-REVIEWED
- Khi AI sửa các hàm này, cần thiết lập để trạng thái review tự động thay đổi
- Nhà phát triển phải luôn kiểm tra xem trạng thái này có chính xác hay không
10. Giảm thiểu độ phức tạp của mã
- Chỉ một dòng mã không cần thiết cũng chiếm chỗ trong cửa sổ ngữ cảnh của AI và làm tăng chi phí
- Nên giữ cấu trúc đơn giản nhất có thể để nâng cao mức độ dễ hiểu cho cả AI lẫn con người
11. Khám phá vấn đề bằng thử nghiệm và prototype
- Có thể tận dụng đặc tính chi phí thấp của việc sinh mã bằng AI để thử nghiệm nhiều hướng giải quyết khác nhau
- Tạo nhiều prototype với đặc tả tối thiểu để khám phá cách tiếp cận tối ưu
12. Tránh sinh mã quy mô lớn một cách bừa bãi
- Với các tác vụ phức tạp, cần chia nhỏ thành các đơn vị nhỏ để AI xử lý theo từng bước
- Ví dụ: tạo từng hàm hoặc class riêng lẻ thay vì toàn bộ dự án
- Cần kiểm chứng xem từng thành phần có phù hợp với đặc tả hay không, và
nếu không thể kiểm soát độ phức tạp của mã thì phải đưa dự án trở lại trạng thái ban đầu
1 bình luận
Ý kiến trên Hacker News
Tôi vẫn cảm thấy quá trình tự tay viết code để sắp xếp suy nghĩ là rất quan trọng
Với tôi, code giống như một cơ chế buộc mình phải mài giũa các chi tiết
Chỉ viết đặc tả thôi thì không cho tôi cảm giác đạt được độ sâu đó
Giao quá trình này cho LLM giống như máy bay bị thất tốc, đầu óc cũng khựng lại
Căng thẳng khi giải quyết vấn đề thì giảm đi, nhưng động lực để suy nghĩ và sáng tạo cũng biến mất
Xung quanh tôi có nhiều người thích để AI viết code thay mình, nhưng tôi không thuộc nhóm đó
Tôi khó tin những người nói rằng chỉ cần uống cà phê rồi chạy 5 agent là có thể làm ra SaaS
Nếu muốn có code chất lượng tốt, tôi nghĩ vẫn cần quá trình tự mình đào sâu vào code
Dù vậy, AI lại khá hữu ích cho các việc lặp đi lặp lại đơn giản như viết test hay xử lý vấn đề cấu hình
Ví dụ, tôi đã hồi sinh lại một dự án từng bỏ dở 5 năm trước bằng Claude, và chỉ trong vài giờ đã cảm thấy tiến được một nửa
Nhưng dạo này tôi có cảm giác đang quay lại với cách tiếp cận lấy đặc tả làm trung tâm
Nhờ agent, việc thử rồi bỏ diễn ra rất nhanh nên tôi vẫn giữ được luồng phát triển lặp
Tôi xem đặc tả và test là sản phẩm thực sự, rồi tiếp tục chỉnh sửa trong đó để sắp xếp suy nghĩ
Chỉ đặc tả thôi thì không thể chứa hết sự phức tạp của thực tế
Code do LLM viết thường dài dòng và đi theo hướng kỳ quặc, nên vẫn cần tự mình kiểm soát
Bù lại, LLM khá ổn khi đóng vai đối tác để thảo luận và gọt giũa ý tưởng
Giờ đây khi việc viết code đã rẻ hơn và nhanh hơn, có lẽ chúng ta lại cần củng cố giai đoạn thiết kế chính thức mạnh hơn
Tôi nghĩ việc thiết lập các công cụ phân tích tĩnh một cách có hệ thống là thứ ảnh hưởng lớn nhất đến chất lượng code
Với TypeScript, tôi kết hợp
tsc,eslint,sonarjs,knip,jscpd,dependency-cruiser,semgreprồi gom vào lệnhpnpm checkTôi cho chúng tự chạy qua pre-commit hook để ngăn các vấn đề mà LLM bỏ sót
Nhờ vậy, ngay cả khi LLM bị khựng lại, tôi vẫn có thể dễ dàng sửa thủ công
Khi style code nhất quán, review sẽ nhẹ nhàng hơn hẳn, và ngay cả khi code AI với code người viết trộn lẫn thì cũng bớt rối hơn
Nhưng dù đã pass cả lint lẫn test, vẫn có thể xuất hiện code hoạt động khác với ý đồ
Ví dụ như API trả về mảng rỗng thay vì 404, tức là đúng về mặt cú pháp nhưng sai về mặt ngữ nghĩa
Kiểu đánh giá độ chính xác về hành vi này vẫn là phần khó nhất hiện nay
Đôi khi nên ưu tiên khả năng bảo trì hơn là các quy tắc lint
Mỗi khi thêm tính năng, tôi đều refactor định kỳ
Cứ sau vài tính năng là tôi lại rà soát và dọn dẹp toàn bộ codebase
Tôi đã code 40 năm, nhưng code hiện tại là thứ khiến tôi hài lòng nhất
Nhưng nhờ LLM, chi phí refactor gần như về 0
Giờ chẳng còn lý do gì để giữ nguyên code tệ
Theo tôi, giá trị thực sự nằm ở việc dùng công cụ tăng hiệu suất để nâng chất lượng
Tôi đã làm một công cụ nội bộ để đánh dấu từng dòng code trong mỗi commit là tốt (xanh lá)/cần refactor (vàng)/cần viết lại (đỏ)
Nó gọn gàng và có hệ thống hơn comment “TODO refactor”, và tôi sắp open source nó
Hiện tại tôi nghĩ phát triển dựa trên đặc tả là cách ổn định nhất để làm việc cùng AI
Tôi dành nhiều thời gian hơn để mài giũa đặc tả và trao đổi ý tưởng với team lẫn AI
Nếu đặc tả không đầy đủ, AI sẽ tạo ra thứ code lạc hướng
Khi hiểu miền bài toán đủ sâu, tôi thường thấy tốt hơn là cho nó triển khai lại từ đầu
Khi đó từng có viễn cảnh rằng “chỉ cần định nghĩa yêu cầu là hệ thống sẽ tự xây xong”
Cuối cùng nó thất bại và Agile lên ngôi, nhưng giờ có vẻ công nghệ lại đang khiến giấc mơ đó trở nên khả thi lần nữa
Giá trị thật sự của AI nằm ở tốc độ và khả năng xử lý sự mơ hồ
Nhưng nếu đi qua đủ mọi thủ tục thì cuối cùng lại chậm như waterfall
Tôi nghĩ thà tự viết code rồi dùng AI làm reviewer vòng đầu còn hơn
Tiến từng bước nhỏ và kiểm chứng nhanh vẫn là cách tiếp cận Agile đúng nghĩa
Đặc biệt là đề xuất đánh dấu các hàm liên quan đến bảo mật. Nhờ vậy có thể giữ được ngữ cảnh khi code thay đổi về sau
“Chia nhỏ vấn đề” là điều cơ bản, nhưng người mới lại rất hay bỏ qua
Buồn cười là dạo này nhờ AI mà mọi người lại phát hiện lại các best practice cơ bản
Thực ra đây đều là những việc lẽ ra phải làm từ lâu rồi
Giờ khi thời gian code giảm xuống, ta lại có thêm khoảng trống để làm những việc này
Hơn nữa, AI thực sự sử dụng tài liệu, nên viết tài liệu tốt giờ mang lại giá trị trực tiếp
Trước đây viết tài liệu xong thường bị phớt lờ, còn LLM thì đọc hết
Trước đây tôi từng viết đặc tả chi tiết trước khi code, nhưng về sau nhận ra lao thẳng vào code lại nhanh hơn
Nhưng giờ có phải chúng ta đang quay lại với cách làm lấy đặc tả làm trung tâm không?
Nếu viết đặc tả khi còn chưa hiểu trọn vấn đề, cuối cùng vẫn sẽ phải vừa code vừa học
Có lẽ hiện tại chúng ta đang ở đâu đó ở giữa hai thái cực đó
Nhưng giờ nhờ AI mà chi phí tạo ra code sai gần như bằng 0, nên tôi có cảm giác giá trị của đặc tả đã giảm đi
Cách này khá giống phương pháp lập trình mà Joe Armstrong từng nói đến
Giờ đây mới là thời điểm nó thật sự khả thi
Khi đảm nhận vị trí lead, tôi từng viết ticket rất chi tiết
Một phần là vì junior, nhưng cũng là để chính tôi không quên các chi tiết
Tuy nhiên, phía quản lý phản đối vì cho là “lãng phí thời gian”, và rồi tôi dần mất thói quen đó
Giờ thì ngược lại, họ lại yêu cầu tôi viết những đặc tả còn tinh vi hơn nữa, mà phải nhanh hơn
Khi dùng AI agent, tôi tò mò về tỷ lệ giữa Markdown và code, cũng như độ dễ đọc của đầu ra
Tôi cũng nghi ngờ không biết thời gian review có thật sự không lâu hơn việc tự viết code hay không
Thật mỉa mai khi dạo này nhiều lập trình viên lại nhiệt tình bảo vệ AI, thứ có thể thay thế chính họ
Liên kết tweet liên quan châm biếm hiện tượng này
Có lẽ thông điệp “không dùng Claude là sẽ tụt lại” xuất phát từ đó
nhưng trên thực tế rất có thể điều đó sẽ dẫn đến nhu cầu tuyển dụng và mức đãi ngộ cho lập trình viên giảm xuống
Đặc biệt, những người chỉ ở mức ghép các package NPM với nhau sẽ càng rủi ro hơn