17 điểm bởi GN⁺ 2025-12-31 | 1 bình luận | Chia sẻ qua WhatsApp
  • Khi các AI agent trở thành trung tâm của việc viết mã, những thực hành tốt vốn từng là “tùy chọn” như kiểm thử, tài liệu hóa và static typing nay đã trở thành yếu tố bắt buộc
  • Yêu cầu 100% code coverage, để mọi dòng mã đều được kiểm chứng thực tế và được hỗ trợ bởi các ví dụ chạy được
  • Làm rõ cấu trúc thư mục và cách đặt tên tệp để LLM dễ khám phá codebase hơn, đồng thời khuyến khích tổ chức tệp theo đơn vị nhỏ
  • Xây dựng môi trường phát triển nhanh, tạm thời và có thể chạy đồng thời để nhiều agent có thể làm việc song song
  • Trọng tâm là duy trì một hệ sinh thái mã mà AI có thể tin cậy thông qua hệ thống kiểu tĩnh và các công cụ kiểm soát chất lượng tự động

AI và tính bắt buộc của “mã tốt”

  • Trong thời gian dài, các lập trình viên đã xem kiểm thử, tài liệu hóa, module nhỏ, static typing là tiêu chuẩn của mã tốt, nhưng trên thực tế chúng thường bị lược bỏ
  • Tuy nhiên, AI agent không giỏi tự dọn dẹp mã, nên những thực hành tốt này trở nên hoàn toàn cần thiết
  • Để agent không đi sai hướng, việc thiết lập guardrail rõ ràng và cưỡng chế thực thi là bắt buộc
  • Khi có guardrail vững chắc, LLM sẽ hội tụ theo đúng lộ trình; còn trong môi trường không hoàn chỉnh, nó sẽ khuếch đại vấn đề

100% code coverage

  • Các nhóm đang bắt buộc 100% code coverage, không chỉ để ngăn lỗi mà còn nhằm xác minh hành vi của toàn bộ mã do agent viết ra
  • Ở mức coverage 95% hay 99,99%, nguồn gốc của phần mã chưa được kiểm thử vẫn không rõ ràng; còn ở mức 100%, mọi dòng chưa được xác minh đều có thể được nhận diện rõ ràng
  • Báo cáo coverage được dùng như danh sách những gì cần kiểm thử, và LLM bắt buộc phải đưa ra ví dụ chạy được mỗi khi thay đổi mã
  • Cách tiếp cận này còn mang lại các hiệu ứng phụ như loại bỏ mã không thể tiếp cận, làm rõ edge case, và cải thiện hiệu quả review code

Namespace và cấu trúc tệp

  • Agent khám phá codebase thông qua hệ thống tệp, nên cấu trúc thư mục và tên tệp đóng vai trò như một giao diện quan trọng
  • Một đường dẫn rõ ràng như ./billing/invoices/compute.ts truyền tải nhiều thông tin hơn hẳn ./utils/helpers.ts
  • Nên ưu tiên các tệp nhỏ, được định nghĩa rõ ràng, vì điều đó cho phép LLM nạp toàn bộ tệp vào ngữ cảnh và tránh suy giảm hiệu năng
  • Kiểu tổ chức này dẫn đến tốc độ và độ chính xác khám phá của agent tốt hơn

Môi trường phát triển nhanh, tạm thời và có thể chạy đồng thời

  • Thay vì một môi trường phát triển đơn lẻ như trước, phát triển dựa trên agent chuyển sang mô hình quản lý nhiều tiến trình song song
  • Fast: quy trình kiểm thử và xác minh phải chạy nhanh; nhóm đã tối ưu để hoàn thành hơn 10.000 assertion trong vòng 1 phút
    • Đạt tốc độ nhờ song song hóa cao, cô lập mạnh, và lớp cache cho các lời gọi bên thứ ba
  • Ephemeral: với lệnh new-feature <name>, có thể tạo môi trường mới trong 1–2 giây, tự động cấu hình và chạy agent
    • Nếu cần thiết lập thủ công thì tần suất sử dụng sẽ giảm mạnh, nên tự động hóa hoàn toàn là yếu tố cốt lõi
  • Concurrent: để có thể chạy nhiều môi trường phát triển cùng lúc, cần thiết lập tránh xung đột cho port, DB, cache, v.v.
    • Có thể dùng Docker hoặc cấu hình cô lập dựa trên biến môi trường

Hệ thống kiểu end-to-end và quản lý chất lượng tự động

  • Tự động hóa càng nhiều thực hành tốt càng tốt để giảm độ tự do của LLM và duy trì chất lượng nhất quán
  • Thiết lập linter và formatter tự động thật nghiêm ngặt, để mỗi khi LLM hoàn thành công việc thì bản sửa tự động được áp dụng
  • Khuyến nghị dùng ngôn ngữ kiểu tĩnh, đặc biệt tận dụng hệ thống kiểu mạnh xoay quanh TypeScript
    • Thông qua những tên kiểu mang ý nghĩa như UserId, WorkspaceSlug, SignedWebhookPayload, có thể biểu đạt rõ ý đồ của mã
  • Dùng OpenAPI để duy trì sự khớp kiểu giữa frontend và backend
  • Tận dụng hệ thống kiểu và trigger của Postgres để bảo đảm tính toàn vẹn dữ liệu, đồng thời tạo client an toàn về kiểu với Kysely
  • Mọi client bên thứ ba cũng cần có định nghĩa kiểu chính xác hoặc được bọc lại trước khi sử dụng

Kết luận: Định nghĩa lại chất lượng mã trong kỷ nguyên AI

  • Agent là những coder xuất sắc và không biết mệt, nhưng hiệu năng của chúng phụ thuộc vào chất lượng môi trường
  • “Mã tốt” không còn là lựa chọn, mà là điều kiện tiên quyết để AI hoạt động đúng cách
  • Thiết lập ban đầu có thể tạo cảm giác nặng nề, nhưng đó là khoản đầu tư bắt buộc đã bị trì hoãn quá lâu
  • Với sự hỗ trợ từ đội ngũ lãnh đạo kỹ thuật, cần hướng tới mục tiêu xây dựng codebase thân thiện với AI

1 bình luận

 
GN⁺ 2025-12-31
Ý kiến trên Hacker News
  • Cái bẫy khi đạt 100% coverage là nếu cùng một agent viết cả code lẫn test, nó có thể rơi vào tự xác thực mâu thuẫn
    Nếu agent tạo ra logic sai và cả test để kiểm chứng nó cũng được viết sai, thì test vẫn pass nhưng code thực tế vẫn có lỗi
    Coverage kiểu này chỉ có ý nghĩa khi test được viết trước code hoặc được con người kiểm định nghiêm ngặt
    Nếu không, nó chỉ tạo ra ảo giác về độ tin cậy mà thôi

    • Bạn nói đúng, nhưng giải pháp không đơn giản là “để con người làm” hay “viết test trước code”
      Điểm cốt lõi là để nhiều con người với các cách tư duy khác nhau kiểm tra điểm mù của nhau
      Dù có nhiều model AI đi nữa thì cuối cùng vẫn nên xem chúng là một “tâm trí” duy nhất
      Tốt nhất là người viết code thì AI viết test, AI viết code thì người viết test, hoặc đôi bên review chéo cho nhau
      Tuy vậy, ngay cả giữa con người với nhau cũng có trường hợp chỉ ý kiến của một người được phản ánh vì quan hệ quyền lực, và AI cũng không ngăn được điều đó
    • Vì vậy cần phải kiểm thử cả test
      Cần cố tình chèn bug vào để xem nó có fail hay không
      Đây không chỉ là vấn đề của AI mà với con người cũng vậy
      Dù sao thì nhờ AI mà nhiều lập trình viên đang học được các nguyên tắc kỹ nghệ phần mềm đúng đắn, đó là điều tốt
    • Có vẻ như sự thay đổi xảy ra không phải ở 100% coverage mà ở 100% coverage MC/DC
      SQLite hay phần mềm hàng không nhắm tới mức này
      Tuy vậy, đây vẫn chưa phải giả thuyết đã được kiểm chứng về mặt học thuật
    • Ngay cả unit test do con người viết tay cũng có cùng vấn đề
      Vì thế cần dùng integration test hoặc UI automation test để kiểm chứng các kịch bản người dùng thực tế
      Dữ liệu lấy từ môi trường production hoặc test trong môi trường shadow cũng hữu ích
    • Thực ra đã có những giải pháp tốt dựa trên code như BDD hay Acceptance Test
      Trước thời LLM thì việc thiết lập khá phiền, nhưng giờ ROI đã tốt hơn
      Như Uncle Bob từng nhấn mạnh, điều quan trọng là đầu tư vào việc cấu trúc test
      LLM viết test lặp đi lặp lại, nhưng nếu yêu cầu thì nó cũng áp dụng tốt nguyên tắc DRY hay factory pattern
  • Đây là cách tôi bắt đầu thử từ hôm qua: viết spec trước bằng TLA+/PlusCal, rồi để Codex triển khai đúng theo spec đó
    Tôi chỉ thị nó phải bám sát spec, không được sáng tạo
    Code tạo ra xấu nhưng chính xác, và nhanh hơn nhiều so với tự tay chuyển dịch
    Tuy vậy, khi tối ưu hóa chưa đủ hoặc quá lộn xộn thì tôi vẫn sửa lại một phần
    Đặc biệt tôi đang thử nghiệm cấu trúc dữ liệu lock-free, nhưng Codex vẫn hay cố dùng lock nên tôi phải tự chỉnh
    Cuối cùng tôi tập trung vào logic toán học, còn AI phụ trách chi tiết triển khai
    Đây chính là luồng lý tưởng của “đặc tả trước, code sau

    • Tôi cũng đang phát triển theo hướng tương tự
      Tôi đồng cảm với bài viết của Martin Kleppmann
    • Gần đây tôi thử lặp lại với Haskell hay Prolog, và mong là sẽ có một nhóm nghiên cứu LLM cùng với mô hình hóa/kiểm chứng
    • Hiệu quả sẽ còn lớn hơn nếu để LLM cũng tham gia viết spec
      Với các model mới nhất, cách này thực sự hoạt động tốt, và hiệu quả chi phí cũng tốt hơn 10~100 lần
  • Cái này nghe như hallucination hoặc bài chào hàng
    Nếu bug production thực tế và gánh nặng bảo trì còn không đủ để ép người ta viết code tốt, thì AI cũng không làm được
    AI ở mức hiện tại thậm chí còn dễ làm code tệ hơn

    • Vấn đề nằm ở giả định rằng “ai cũng biết code tốt là gì”
      Ngay cả độ dài method còn chưa có đồng thuận, thì không tồn tại tiêu chuẩn chất lượng phổ quát
      Các chỉ số như test coverage cũng rất dễ bị thao túng, và nếu áp dụng sai còn phản tác dụng
    • Test coverage không phải vật thay thế cho code tốt
      Đặc biệt khi AI viết test, nó có thể tạo ra sự tự tin giả tạo
    • Tác giả bài gốc là CEO công ty AI nên có thể cũng có thiên kiến /s
  • Tôi nghĩ phát triển phần mềm có thể là ứng dụng thực tiễn duy nhất của LLM
    So với các lĩnh vực khác, ở đây có thể tạo vòng phản hồi nhanh hơn nhiều
    Ta lập kế hoạch với LLM rồi vài giờ sau xác nhận thất bại, khi đó LLM sẽ nói “đó là lý do không nên làm vậy”
    Nó giống như xây một căn nhà theo chuẩn điện của Mỹ rồi đến lúc lắp máy rửa chén chuẩn Canada mới phát hiện vấn đề

    • Vì vậy mà các ngành kỹ thuật khác có quy tắc nghiêm ngặt và chế độ chứng chỉ
      Phần mềm tương đối an toàn nên trước đây có thể phát triển ẩn danh, nhưng giờ đang hình thành văn hóa ký tên chịu trách nhiệm
      Trong tương lai có khi chỉ những người viết code rủi ro cao, nhiều đổi mới mới được trả lương cao
    • Nhưng tôi không hiểu vì sao trải nghiệm như vậy lại dẫn đến kết luận rằng LLM hữu ích
      AI cứ tiếp tục sinh ra đoạn code vô nghĩa, ta debug, rồi nó lại sinh ra thứ vô nghĩa khác, chỉ rơi vào vòng lặp vô hạn
    • Máy rửa chén chuẩn Canada vẫn lắp được
      Chỉ cần khớp đúng chuẩn dòng điện là an toàn
    • Nếu nghĩ tới simulator hay digital twin, thì vẫn có thể tạo vòng phản hồi mà không cần xây ngoài đời thực
      Dù vậy tôi vẫn thấy may là với unit test ta còn có điểm chạm với thực tế
    • Nói rằng “ngoài phần mềm ra thì không có ứng dụng thực tiễn nào” là một nhận định kiêu ngạo
      Tôi đang dùng LLM để học về mạch RLC và inerter
  • Nhiều người thấy LLM sinh code nhanh thì ngạc nhiên, nhưng tốc độ hay số lượng không phải nút thắt của chất lượng
    Cuộc cách mạng thực sự sẽ đến khi AI tạo ra code chính xác hơn con người

    • Dùng LLM khiến kỹ sư ngày càng xa rời sự hiểu biết về cách hệ thống thực sự được triển khai
      Giá trị thật sự đến từ việc biết code hoạt động như thế nào
      Giữa những kỹ sư chỉ đoán mò trong cuộc họp, khoảnh khắc một người mở đoạn code thật ra cho mọi người xem mới là khoảnh khắc có giá trị nhất
  • “Code tốt” có lẽ là loại code được tối ưu theo bộ nhớ làm việc hữu hạn của con người
    Model có thể nhìn toàn bộ ngữ cảnh cùng lúc nên không bị ràng buộc như vậy
    Nếu context window lớn hơn 100 lần thì có khi kiểu tranh luận này sẽ bớt quan trọng đi

  • Tôi lo rằng nếu yêu cầu LLM đạt 100% coverage thì các giả định sai sẽ bị cố định hóa
    Dù vậy, nếu vẫn có review của con người thì chắc vẫn có thể nói “cái này sai rồi, xóa test đi và viết lại chứ?”

    • Đúng vậy, vẫn là con người review test case
      LLM cùng viết PRD theo kiểu phỏng vấn để làm rõ phạm vi và kỳ vọng
    • Trên thực tế LLM tạo ra rất nhiều test vô nghĩa kiểu như “1=1 phải không?”
  • Best practice” thay đổi theo môi trường công nghệ
    Giờ việc viết code đã dễ hơn nên 100% coverage có thể hữu ích hơn cho LLM
    Test cho LLM một mục tiêu rõ ràng, và giúp các tương tác về sau an toàn hơn

    • Với những hệ thống tiến hóa lâu dài, test là đường sống
      Mỗi test tham chiếu tới ticket bug trong quá khứ và đảm bảo bản sửa lỗi tiếp tục được duy trì
    • “Best practice” dù triển khai khác nhau thì pattern vẫn tương tự
      Nếu đưa kịch bản cho LLM, phần lớn nó sẽ sinh ra code có chất lượng gần tương đương nhau
      Khác với nghệ thuật sáng tạo, phần mềm là ngành đặc biệt phù hợp để tự động hóa
  • Khi đọc bài này tôi tưởng nội dung sẽ là “để AI hiệu quả thì chúng ta phải viết code tốt
    Thực tế Claude thường mắc lỗi với tên biến mơ hồ hoặc code phi logic
    Nếu tên biến là “iteration_count” nhưng lại chứa tổng, AI sẽ bị đánh lừa
    Cuối cùng thì code sạch giúp ích cho cả AI lẫn con người

    • Nhờ AI mà cả team bắt đầu chú ý hơn tới tài liệu hóa và quản lý comment
      Vì AI dùng tài liệu nội bộ làm nguồn học, nên giờ tài liệu được cập nhật được xem là bắt buộc
      Trước đây nó có ưu tiên thấp, nhưng giờ lại ảnh hưởng trực tiếp tới chất lượng model
    • Con người nhớ được ngữ cảnh của đoạn code đã xem một lần, còn AI thì phải học lại từ đầu ở mỗi session
      Dù vậy theo thời gian thì phần này cũng sẽ được cải thiện
    • Cách hiệu quả là ghi rõ ý đồ và logic bằng method signature cùng comment
      Làm vậy sẽ tăng khả năng LLM triển khai chính xác ngay từ lần đầu
  • Bài này cho thấy mức độ hiểu biết kỹ thuật hời hợt của các công ty làm prompt
    100% coverage không thể xác minh mọi tổ hợp đầu vào
    Nó chỉ đơn giản là chạy qua mọi dòng bằng một vài ví dụ
    Cuối cùng vẫn cần tới chứng minh hình thức, mà thứ đó thì đắt đỏ đến mức khổng lồ và LLM không giúp được gì

    • Vậy giải pháp là gì? Một senior nhìn PR rồi nói “LGTM” thì cũng chỉ là bài test cảm tính
      Ngược lại, tạo ra môi trường phát triển có tính phản hồi bằng test có thể mở ra một thời kỳ hoàng kim mới
      Nếu coverage có vấn đề thì sau này mở rộng thêm cũng được
      Tốt hơn là ngay từ đầu hãy thiết lập test kỹ lưỡng nhất có thể
    • Nói LLM vô dụng với formal verification là hơi quá
      Đã có nhiều thử nghiệm kết nối nó với proof assistant
      Ngay cả khi đặc tả có chút lỗi, phần lớn trường hợp nó vẫn cho ra kết quả dùng được