VietTechiesHIỂU CÔNG NGHỆ. MỞ GÓC NHÌN.
☰ Chuyên mục

Quy tắc viết code của Brian Kernighan: Quá thông minh thì chính bạn cũng khó debug

06/10/2026 · VietTechies · Biên tập

Brian Kernighan phát biểu trước micro tại Vintage Computer Festival East năm 2025.


Brian Kernighan đã dành hàng chục năm làm việc với những phần mềm có ảnh hưởng lớn nhất lịch sử máy tính. Một nguyên tắc ông liên tục nhắc lại đơn giản đến mức gần như khó tin: nếu code của bạn quá “thông minh”, đến lúc lỗi xảy ra có thể chính bạn cũng không còn đủ khả năng để sửa nó.

Brian Kernighan làm việc 30 năm tại Bell Labs, trong nhóm máy tính gắn với sự phát triển của Unix, rồi trở thành giáo sư khoa học máy tính tại Princeton. Ông đồng tác giả The C Programming Language cùng Dennis Ritchie và viết nhiều cuốn sách có ảnh hưởng lớn về phong cách lập trình, công cụ và ngôn ngữ.

Với lý lịch như vậy, lời khuyên của ông về code lại chẳng mấy hào nhoáng.

“Debugging khó gấp đôi việc viết code ngay từ đầu.”

Phần còn lại của ý tưởng gần như tự suy ra: nếu khi viết chương trình bạn đã dùng hết mức độ “khéo léo” của mình, thì khi chương trình hỏng, bạn không còn dư địa trí tuệ để hiểu và sửa nó.

Nghe giống một câu đùa về lập trình viên. Thực ra đây là một nguyên tắc về độ phức tạp.

Giải pháp “clever” luôn có một khoản phí ẩn

Khi code đang chạy, sự khéo léo có thể trông rất hiệu quả. Một biểu thức dày đặc thay cho mười dòng bình thường. Một abstraction tổng quát xử lý sáu trường hợp cùng lúc. Một thủ thuật ngắn tiết kiệm một vòng lặp, một allocation hoặc một hàm.

Rồi ba tháng trôi qua.

Người đọc code không còn giữ toàn bộ bài toán trong đầu. Những giả định ban đầu đã phai đi. Một lỗi production xuất hiện ở tình huống không ai dự đoán. Và người phải đọc code dưới áp lực có thể không phải người đã viết nó.

Đến lúc đó, chi phí thật của sự “thông minh” mới xuất hiện.

Câu hỏi quan trọng không còn là “Tôi đã viết ít dòng đến mức nào?” mà là “Tôi phải giữ bao nhiêu ý niệm cùng lúc trong đầu để hiểu đoạn code này có thể làm gì?”.

Các công trình đầu tiên của Kernighan về phong cách lập trình đi đúng vào điểm này. Mục tiêu không phải làm giảm trình độ lập trình viên. Mục tiêu là khiến người khác dễ suy luận về chương trình hơn.

Code dễ đọc không có nghĩa là code dành cho người mới

Nhiều người nghe “hãy giữ mọi thứ đơn giản” rồi hiểu thành “đừng dùng kỹ thuật nâng cao”. Đó không phải vấn đề.

Một hệ thống phức tạp có thể thật sự cần ý tưởng phức tạp. Kỷ luật nằm ở chỗ không để sự phức tạp lan ra khắp nơi.

Nếu một phần hệ thống thật sự cần thuật toán khó, hãy cô lập nó. Đặt tên để người khác hiểu nó làm gì. Ghi rõ giả định. Test các trường hợp biên. Và giữ cho phần còn lại nhàm chán nhất có thể.

Code tốt không chứng minh tác giả biết nhiều đến đâu. Nó làm giảm lượng kiến thức mà người đọc tiếp theo phải giữ trong đầu cùng lúc.

Đó là lý do khi mở rộng quy mô, sự rõ ràng phát huy hiệu quả tốt hơn sự khéo léo. Một người rất giỏi có thể hiểu một thủ thuật. Nhưng cả team, người bảo trì sau này, người xử lý incident và chính bạn lúc 2 giờ sáng đều cần thứ bền vững hơn.

Phần lớn việc debug bắt đầu từ trước khi bug xuất hiện

Trong các tài liệu sau này về debugging, Kernighan và Rob Pike nhấn mạnh rằng phần lớn bug khá bình thường, và debug tốt bắt đầu bằng việc xem bằng chứng rồi suy ngược từ điều chương trình thực sự đã làm.

Quá trình đó dễ hơn rất nhiều khi code có ranh giới rõ.

Hàm nhỏ thu hẹp vùng tìm kiếm. State được biểu diễn rõ khiến chuyển trạng thái sai dễ thấy. Tên tốt giữ lại ý định. Test biến giả định thành ví dụ có thể chạy. Log đúng thông tin có thể biến nhiều giờ đoán mò thành vài phút.

Không kỹ thuật nào trong số đó trông ngoạn mục.

Chính vì vậy chúng mới hiệu quả.

Kỷ nguyên AI khiến nguyên tắc này quan trọng hơn, không phải kém đi

AI hiện có thể sinh ra code trông có vẻ chạy được nhanh hơn tốc độ phần lớn team có thể review. Điều đó thay đổi điểm nghẽn.

Viết code đang rẻ đi. Hiểu code thì không.

Một hàm do AI sinh ra có thể compile. Có thể vượt qua bài test happy path. Thậm chí trông khá đẹp. Nhưng bài toán bảo trì vẫn thuộc về con người: nó đã giả định điều gì? Khi thất bại thì sao? Abstraction này có thực sự cần không? Hành vi nào có chủ ý, hành vi nào chỉ vô tình xuất hiện từ cách triển khai được sinh ra?

Nếu một công cụ có thể tạo 500 dòng trong vài giây, ta rất dễ đo tiến độ bằng lượng output. Nhưng phần mềm không có giá trị vì có nhiều dòng code. Nó có giá trị vì hệ thống vẫn đủ dễ hiểu để thay đổi một cách an toàn.

Code được tạo càng nhanh, code khó đọc càng trở nên đắt đỏ.

Bốn câu hỏi cho mỗi pull request

Tôi có thể giải thích đoạn này mà không phải chạy từng dòng trong đầu không? Nếu không, abstraction có thể đang che quá nhiều hoặc quá ít.

Khi nó hỏng, tôi sẽ nhìn vào đâu đầu tiên? Nếu câu trả lời là “khắp nơi”, ranh giới hệ thống đang yếu.

Phiên bản bình thường có thể dài hơn một chút nhưng dễ kiểm chứng hơn nhiều không? Đôi khi vài dòng thêm rẻ hơn vài tầng suy nghĩ.

Người tiếp theo có hiểu tại sao đoạn này tồn tại không? Code lưu hành vi. Tên, cấu trúc và comment lưu ý định.

Sẽ luôn có những lúc giải pháp thông minh thật sự là giải pháp đúng.

Nhưng sự “thông minh” nên được sử dụng có chủ đích trong hệ thống, thay vì là thứ lập trình viên mặc định phô diễn.

Lời cảnh báo của Kernighan tồn tại lâu như vậy vì phần cứng đã đổi, ngôn ngữ đã đổi, và giờ AI đang đổi cách code được tạo ra — nhưng người debug ở cuối chuỗi vẫn chỉ có một bộ não hữu hạn.

Bao nhiêu phần code mà bạn tự hào nhất hôm nay vẫn sẽ trông “hiển nhiên” với người phải sửa nó sau một năm?

Đọc bằng ngôn ngữ khác: English · Español · Deutsch · Français · Português (Brasil) · Tiếng Việt

Nguồn