Comment Code Sao Cho Chuẩn? 9 Quy Tắc Ai Cũng Cần Biết
Các Phương Pháp Viết Comment Code Hiệu Quả Nhất Dành Cho Lập Trình Viên
Giới Thiệu
Giáo sư nổi tiếng Hal Abelson từ MIT từng nói: "Chương trình nên được viết để con người đọc hiểu, và chỉ phụ thuộc vào máy tính thực thi một cách ngẫu nhiên." Dù có thể đã cố ý giảm nhẹ tầm quan trọng của việc code chạy được, ông hoàn toàn đúng khi nhận định rằng code có hai đối tượng tiếp cận hoàn toàn khác biệt.
Trình biên dịch và thông dịch bỏ qua tất cả comments và xem mọi chương trình hợp lệ cú pháp đều dễ hiểu như nhau. Nhưng với con người thì khác - chúng ta thấy một số đoạn code khó hiểu hơn những phần khác, và chúng ta phụ thuộc vào comments để giúp giải mã chúng.
Trong khi có vô số tài nguyên giúp lập trình viên viết code tốt hơn (sách, công cụ phân tích tĩnh...), lại cực kỳ ít tài liệu hướng dẫn viết comments chất lượng. Dễ dàng đo lường số lượng comments trong codebase, nhưng đánh giá chất lượng comments thì khó khăn hơn nhiều - và hai yếu tố này không phải lúc nào cũng tương quan với nhau. Một comment tồi thậm chí còn tệ hơn không có comment nào.
Như Peter Vogel đã phân tích:
- Viết và duy trì comments tốn chi phí
- Trình biên dịch không kiểm tra comments nên không thể xác minh tính đúng đắn của chúng
- Trong khi đó, bạn có thể chắc chắn rằng máy tính sẽ thực thi chính xác những gì code yêu cầu
Dù những nhận định trên đều đúng, việc đi đến cực đoan không bao giờ viết comments cũng là sai lầm. Dưới đây là 9 quy tắc giúp bạn đạt được sự cân bằng hoàn hảo:
9 Quy Tắc Vàng Để Viết Comments Hiệu Quả
Quy Tắc 1: Comments Không Nên Lặp Lại Code
Nhiều lập trình viên mới vào nghề có thói quen comment quá mức do được đào tạo từ các khóa học nhập môn. Ví dụ điển hình:
if (x > 3) {
...
} // if
Tôi thậm chí còn nghe về các giảng viên yêu cầu sinh viên comment từng dòng code. Dù có thể hợp lý với người mới bắt đầu hoàn toàn, những comments này giống như bánh xe phụ cần được tháo bỏ khi đã vững tay nghề.
Những comments không thêm thông tin có giá trị âm vì:
- Tăng thêm sự lộn xộn về mặt hình ảnh
- Tốn thời gian để viết và đọc
- Có thể trở nên lỗi thời
Ví dụ kinh điển về comment vô giá trị:
i = i + 1; // Cộng thêm 1 vào i
Quy Tắc 2: Comments Tốt Không Phải Lời Bào Chữa Cho Code Khó Hiểu
Một cách lạm dụng comments khác là dùng chúng để cung cấp thông tin lẽ ra nên nằm trong chính code. Ví dụ đơn giản:
private static Node getBestChildNode(Node node) {
Node n; // best child node candidate
for (Node node: node.getChildren()) {
// update n if the current state is better
if (n == null || utility(node) > utility(n)) {
n = node;
}
}
return n;
}
Có thể loại bỏ hoàn toàn nhu cầu comment bằng cách đặt tên biến rõ ràng hơn:
private static Node getBestChildNode(Node node) {
Node bestNode;
for (Node currentNode: node.getChildren()) {
if (bestNode == null || utility(currentNode) > utility(bestNode)) {
bestNode = currentNode;
}
}
return bestNode;
}
Như Kernighan và Plauger đã viết trong "The Elements of Programming Style": "Đừng comment code tệ - hãy viết lại nó."
Quy Tắc 3: Nếu Bạn Không Thể Viết Comment Rõ Ràng, Có Lẽ Code Có Vấn Đề
Comment nổi tiếng nhất trong mã nguồn Unix: "Bạn không cần hiểu đoạn này" xuất hiện trước một đoạn code phức tạp về chuyển đổi ngữ cảnh. Dennis Ritchie sau này giải thích rằng ý ông là "Đoạn này sẽ không có trong bài thi" chứ không phải thách thức người đọc. Nhưng hóa ra, chính ông và Ken Thompson cũng không thực sự hiểu nó và sau này phải viết lại.
Điều này gợi nhớ đến Định luật Kernighan: "Debug khó gấp đôi viết code. Vì vậy, nếu bạn viết code một cách thông minh nhất có thể, thì theo định nghĩa, bạn không đủ thông minh để debug nó."
Cảnh báo người đọc tránh xa đoạn code của bạn giống như bật đèn hazard trên xe hơi: thừa nhận bạn đang làm điều gì đó mà bạn biết là không ổn. Thay vào đó, hãy viết lại code sao cho đủ đơn giản để bạn có thể giải thích được.
Quy Tắc 4: Comments Nên Giải Tỏa Nghi Ngờ, Không Gây Thêm Thắc Mắc
Không thể bàn về comments tồi mà không nhắc đến câu chuyện từ cuốn "Hackers: Heroes of the Computer Revolution" của Steven Levy:
[Peter Samson] đặc biệt khó hiểu khi từ chối thêm comments giải thích những gì anh ấy đang làm vào mã nguồn. Một chương trình nổi tiếng Samson viết gồm hàng trăm dòng lệnh assembly, với duy nhất một comment bên cạnh dòng chứa số 1750. Comment đó viết "RIPJSB", và mọi người phải vắt óc suy nghĩ ý nghĩa cho đến khi ai đó nhận ra 1750 là năm Bach qua đời, và Samson đã viết tắt cho "Rest In Peace Johann Sebastian Bach".
Dù tôi cũng thích những mẹo hay như bất kỳ ai, đây không phải là ví dụ nên làm theo. Nếu comment của bạn gây bối rối thay vì làm sáng tỏ vấn đề, hãy xóa nó đi.
Quy Tắc 5: Giải Thích Code Không Theo Chuẩn Thông Thường Trong Comments
Nên comment những đoạn code mà người khác có thể xem là thừa hoặc không cần thiết, như ví dụ từ App Inventor (nguồn của tất cả các ví dụ tích cực trong bài):
final Object value = (new JSONTokener(jsonString)).nextValue();
// Lưu ý: JSONTokener.nextValue() có thể trả về
// giá trị equals() null
if (value == null || value.equals(null)) {
return null;
}
Không có comment, ai đó có thể "đơn giản hóa" code hoặc xem nó như câu thần chú bí ẩn. Hãy tiết kiệm thời gian và lo lắng cho người đọc sau bằng cách giải thích lý do đoạn code tồn tại.
Cần có sự phán đoán để quyết định khi nào code cần giải thích. Khi học Kotlin, tôi bắt gặp code trong một tutorial Android có dạng:
if (b == true)
Tôi ngay lập tức tự hỏi liệu có thể thay bằng:
if (b)
như trong Java. Sau khi nghiên cứu, tôi hiểu rằng biến Boolean nullable được so sánh rõ ràng với true để tránh kiểm tra null phức tạp:
if (b != null && b)
Tôi khuyên không nên comment những idiom thông thường trừ khi bạn đang viết tutorial cho người mới.
Quy Tắc 6: Cung Cấp Liên Kết Đến Nguồn Gốc Của Code Sao Chép
Nếu giống đa số lập trình viên, đôi khi bạn sử dụng code tìm được trên mạng. Bao gồm tham chiếu đến nguồn gốc giúp người đọc sau hiểu được bối cảnh đầy đủ như:
- Vấn đề đang được giải quyết
- Ai cung cấp code
- Tại sao giải pháp này được đề xuất
- Nhận xét của cộng đồng về nó
- Liệu nó còn hoạt động không
- Cách cải tiến
Ví dụ:
/** Chuyển đổi Drawable thành Bitmap. via https://stackoverflow.com/a/46018816/2219998. */
Theo liên kết đến câu trả lời, ta thấy:
- Tác giả code là Tomáš Procházka, top 3% trên Stack Overflow
- Một commenter đề xuất tối ưu đã được tích hợp
- Commenter khác gợi ý cách tránh edge case
So sánh với comment kiểu này (đã chỉnh sửa để bảo vệ danh tính):
// Công thức thần kỳ lấy từ Stack Overflow, được cho là
// liên quan đến nhận thức thị giác con người
return (int) (0.3 * red + 0.59 * green + 0.11 * blue);
Người muốn hiểu code này sẽ phải tự tìm công thức. Dán URL sẽ tiết kiệm thời gian hơn nhiều.
Một số lập trình viên ngại thừa nhận không tự viết code, nhưng tái sử dụng code có thể là quyết định thông minh, tiết kiệm thời gian và mang lại lợi ích từ nhiều góc nhìn. Dĩ nhiên, đừng bao giờ dán code bạn không hiểu.
Code từ Stack Overflow thường thuộc giấy phép Creative Commons yêu cầu ghi công. Comment tham chiếu đáp ứng yêu cầu này.
Tương tự, nên tham chiếu các tutorial hữu ích như lời cảm ơn đến tác giả:
// Cảm ơn Chris Veness tại http://www.movable-type.co.uk/scripts/latlong.html
// vì tài liệu tham khảo và ví dụ tuyệt vời
Quy Tắc 7: Bao Gồm Liên Kết Đến Tài Liệu Tham Khảo Bên Ngoài Khi Cần Thiết
Dĩ nhiên không phải mọi tham chiếu đều đến Stack Overflow. Ví dụ:
// http://tools.ietf.org/html/rfc4180 gợi ý dòng CSV
// nên kết thúc bằng CRLF, do đó dùng \r\n
csvStringBuilder.append("\r\n");
Liên kết đến tiêu chuẩn và tài liệu khác giúp người đọc hiểu vấn đề code đang giải quyết. Dù thông tin có thể nằm trong tài liệu thiết kế, comment đặt đúng chỗ cung cấp chỉ dẫn khi cần nhất. Trong trường hợp này, liên kết cho thấy RFC 4180 đã được cập nhật bởi RFC 7111 - thông tin hữu ích.
Quy Tắc 8: Thêm Comments Khi Sửa Lỗi
Nên thêm comments không chỉ khi viết code mới mà cả khi sửa đổi, đặc biệt là sửa lỗi. Xem comment này:
// LƯU Ý: Ít nhất trên Firefox 2, nếu người dùng kéo ra ngoài
// cửa sổ trình duyệt, sự kiện mouse-move (và cả mouse-down)
// sẽ không được nhận cho đến khi người dùng kéo lại vào trong
// Có giải pháp tạm trong hàm onMouseLeave()
@Override
public void onMouseMove(Widget sender, int x, int y) { .. }
Comment không chỉ giúp hiểu code hiện tại và hàm được tham chiếu, mà còn hữu ích để xác định liệu code còn cần thiết và cách kiểm tra nó.
Cũng hữu ích khi tham chiếu issue tracker:
// Dùng name làm title nếu properties không có (issue #1425)
Dù git blame có thể tìm commit thêm/sửa dòng code, message commit thường ngắn gọn, và thay đổi quan trọng (như sửa issue #1425) có thể không nằm trong commit gần nhất (vd: di chuyển method giữa các file).
Quy Tắc 9: Dùng Comments Đánh Dấu Triển Khai Chưa Hoàn Thiện
Đôi khi cần check-in code dù biết nó có hạn chế. Dù có thể muốn giấu đi các khiếm khuyết trong code, tốt hơn nên làm chúng rõ ràng, ví dụ bằng comment TODO:
// TODO(hal): Hiện đang dùng dấu chấm thập phân,
// bất kể locale của điện thoại. Cần cân nhắc
// hỗ trợ dấu phẩy, đòi hỏi cập nhật phần phân tích
// số và các nơi chuyển số thành chuỗi như FormatAsDecimal
Dùng định dạng chuẩn cho các comment này giúp đo lường và xử lý technical debt. Tốt hơn nữa, tạo issue trong tracker và tham chiếu trong comment.
Kết Luận
Hy vọng các ví dụ trên đã cho thấy comments không phải để bào chữa hay sửa bad code ; chúng bổ sung cho code bằng loại thông tin khác biệt. Như Jeff Atwood - đồng sáng lập Stack Overflow từng viết: "Code Tells You How, Comments Tell You Why".
Tuân theo các quy tắc này sẽ giúp bạn và đồng đội tiết kiệm thời gian, đọc code clear hơn.
Tham khảo:
https://www.reddit.com/r/ProgrammerHumor/comments/8w54mx/code_comments_be_like/
All rights reserved