Tiêu chuẩn coding trong Java (Coding Standards)

Trong bài viết này tôi sẽ giới thiệu với các bạn tiêu chuẩn coding trong Java và tầm quan trọng của việc viết code theo chuẩn. Mỗi ngôn ngữ lập trình và dự án phát triển sẽ có những tiêu chuẩn khác nhau. Phạm vi trong bài này chỉ giới thiệu một vài tiêu chuẩn chung của ngôn ngữ lập trình Java.

Nếu các bạn là người mới bắt đầu tìm hiểu về Java hoặc đã biết về Java nhưng chưa biết coding standard là gì thì hãy dành ít thời gian đọc qua và áp dụng.

1. Tiêu chuẩn coding là gì?

Tiêu chuẩn coding (Coding Standards) là một bộ quy tắc quy định cách viết code của một chương trình mà lập trình viên phải tuân theo khi tham gia vào dự án phát triển chương trình đó. Tùy theo mỗi dự án mà sẽ có những tiêu chuẩn khác nhau, bộ quy tắc đó bao gồm:

  • Đặt tên lớp, interface, tên biến, phương thức, …
  • Khoảng trắng, tab
  • Khai báo và sử dụng biến
  • Comment mã nguồn: tên người tạo, phiên bản, ngày tạo file, lớp, phương thức, người thay đổi, nội dung thay đổi, …
  • Độ dài tối đa mỗi dòng code, mỗi file, …
  • …..

2. Tầm quan trọng của tiêu chuẩn coding

  • Dễ bảo trì, sửa lỗi.
  • Để người khác hiểu được mã nguồn của mình.
  • Thống nhất code giữa các thành viên trong nhóm.

Bạn là một Debugger xuất sắc, có người nhờ bạn sửa lỗi chương trình giúp họ:

Bạn cảm thấy như thế nào nếu được nhận bảo trì đoạn code này so với đoạn code trên:

Tiêu chuẩn coding là một thành phần rất quan trọng trong phát triển phần mềm. Tuy nhiên, nó thường bị bỏ qua hoặc chỉ áp dụng giai đoạn đầu, về sau lại bị bỏ quên.

Một tiêu chuẩn mã hoá nhất quán sẽ giúp cải thiện chất lượng của hệ thống phần mềm tổng thể. Chìa khóa cho một tiêu chuẩn mã hóa tốt là tính nhất quán. Sự nhất quán này cần được tìm thấy trong tiêu chuẩn (nói cách khác, bạn cần đảm bảo rằng các nguyên tắc không mâu thuẫn nhau) mà còn trong mã nguồn sử dụng tiêu chuẩn. Mã nguồn đã hoàn thành nên phản ánh một phong cách hài hòa, như thể một nhà phát triển đã viết mã trong một chương trình.

Nếu bạn là người duy nhất có thể hiểu được mã (cả cấu trúc và chức năng), bạn sẽ là người duy nhất có thể thực hiện thay đổi và sửa lỗi cho mã đó. Đây là những gì bạn muốn, phải không? Bằng cách đó, bạn sẽ không bao giờ có thể để lại sản phẩm đó cho người khác và tạm ứng sự nghiệp của bạn.

Mã nguồn có thể đọc được nhiều hơn thì dễ dàng hơn cho người nào đó duy trì mã đó. Bằng cách theo một phong cách nhất quán, nó cho phép các nhà phát triển khác bước vào và giúp bảo trì hoặc phát triển mới.

Bằng cách tạo mã nguồn dễ hiểu hơn cho nhà phát triển, sẽ dễ dàng tìm và sửa lỗi hơn. Nó cũng cung cấp một cái nhìn tốt hơn về cách thức mã đó phù hợp với ứng dụng lớn hơn, và trong một số trường hợp, công ty như một toàn thể. Quan điểm rõ ràng hơn này có thể dẫn đến khả năng tái sử dụng mã nhiều hơn, có thể có ảnh hưởng đáng kể đến chi phí và nỗ lực phát triển.

Cũng có một yếu tố tâm lý đóng vai trò khi áp dụng các tiêu chuẩn mã. Yếu tố này là cảm giác “quyền sở hữu mã”. Quyền sở hữu mã liên quan đến cảm giác tự hào về chất lượng công việc đã thực hiện và mong muốn thấy mã (sản phẩm) đó hoạt động tốt. Mức sở hữu càng cao, chất lượng càng trở nên tốt hơn.

3. Chuẩn hình thức và chuẩn ngữ nghĩa

3.1. Chuẩn hình thức

Là những quy định liên quan đến sự định dạng của mã nguồn:

  • Thụt đầu dòng
  • Sử dụng khoảng trắng
  • Đóng ngoặc, mở ngoặc
  • Đặt tên lớp, thuộc tính, phương thức

3.2. Chuẩn ngữ nghĩa

Là những quy định liên quan đến sự thực thi của mã nguồn

  • Biểu thức so sánh
  • Cấu trúc điều khiển : if, for, while
  • Khai báo và sử dụng biến
  • Cài đặt phương thức

4. White Space

Những quy định về sử dụng khoảng trắng (space), thụt đầu dòng, xuống dòng, dòng trống: giúp cho nội dung văn bản được tổ chức một cách có hệ thống để người đọc dễ dàng tiếp thu.

4.1. White Space – thụt đầu dòng

Xác định một chuẩn thụt đầu dòng cho toàn bộ mã nguồn của chương trình.

  • 1 đơn vị thụt đầu dòng = 1 tab(*)
  • Hoặc, 1 đơn vị thụt đầu dòng = 5 khoảng trắng

Dòng code thứ 20 dùng 2 đơn vị thụt đầu dòng nghĩa là bấm tab 2 lần(*)

Nên dùng tab thay cho khoảng trắng

  • Đỡ tốn công nhập quá nhiều lần khoảng trắng
  • Có thể tùy chỉnh một đơn vị tab ứng với bao nhiêu khoảng trắng tùy ý

Hai dòng code cách nhau một bậc thì sẽ cách nhau một đơn vị thụt đầu dòng.

4.2. White Space – Dòng trống

Những dòng code có quan hệ với nhau (cùng thực hiện một công việc) thì gom lại thành một block.

Nghĩa là không có dòng trống giữa các đoạn code như trên.

Hai block code thì cách nhau ít nhất một dòng trống.

Đặt khoảng trắng sau dấu phẩy và dấu chấm phẩy.

Đặt khoảng trắng xung quanh các toán tử.

5. Ngoặc tròn ()

Dùng dấu ngoặc tròn để:

  • Người đọc hiểu rõ mục đích của bạn.
  • Chắc chắn là trình biên dịch sẽ thực hiện đúng theo ý của bạn.

Hãy quyết định dùng dấu ngoặc tròn khi bạn đang phân vân là có nên dùng dấu ngoặc tròn hay không.

6. Dấu ngoặc nhọn {}

Theo tiêu chuẩn Java: dấu “{” phải được đặt cùng dòng với các câu if, for, while,… Nếu bạn nào đã code với C# thì sẽ thấy ngược lại, dấu “{” phải được đặt ở dòng mới.

7. Comment

Không viết các comment chỉ lặp code, comment thừa. Một số vấn đề gặp phải khi comment không tốt:

  • Các comment chỉ mô tả là lặp code, chứ không cung cấp thêm thông tin gì cho người đọc.
  • Làm code dài hơn.
  • Người đọc tốn thời gian đọc nhiều hơn.

Viết các comment không cầu kì; càng đơn giản càng tốt.

Khi dùng nhiều endline comment trên các dòng code liên tiếp nhau thì các comment này phải được canh lề như nhau.

Nên vừa code vừa viết comment. Tránh trường hợp viết code xong rồi mới viết comment.

Không nên đụng chỗ nào cũng comment, chỉ viết comment khi bạn cảm nhận là đoạn code của mình quá phức tạp.

8. Quy ước đặt tên

8.1. Quy tắc viết hoa

Pascal case

  • Các chữ cái đầu mỗi từ được viết hoa.
  • Các chữ còn lại được viết thường.
  • Ví dụ: MyProvider, StringBuilder

Camel case

  • Giống với Pascal case nhưng chữ cái đầu của từ đầu tiên viết thường.
  • Ví dụ: myProvider, stringBuilder

8.2. Đặt tên class,  interface, abstract class

Sử dụng danh từ hay cụm danh từ : SinhVien, FormSinhVien,…

Dùng Pascal case : SinhVien, FormSinhVien,…

Hạn chế viết tắt gây khó hiểu :

  • Sai: FormSV
  • Đúng:FormSinhVien

Không dùng tiền tố khi đặt tên lớp:

  • Sai : ISinhVien
  • Đúng: SinhVien

8.3. Phương thức

Sử dụng Camel case để đặt tên phương thức. Ví dụ: xepLoai.

Tên phương thức thể hiện được chức năng của phương thức đó. tinhDiemTrungBinh.

Tránh đặt tên gây cảm giác mơ hồ, không rõ nghĩa. Ví dụ: hienThi, tinh.

Không phân biệt tên các phương thức bằng số. Ví dụ: tinhDiem1, tinhDiem2.

8.4. Biến

Sử dụng Camel case để đặt tên biến. Ví dụ: int diemTrungBinh, String hoTen

Không dùng tiền tố. Ví dụ:

  • Đúng: String address
  • Sai: String strAddress

Tên biến gợi nhớ, tránh viết tắt gây khó hiểu. Ví dụ:

  • Đúng: String address
  • Sai: String addr

Không đặt tên biến chỉ bằng 1 chữ cái như x, y , z,… trừ trường hợp các biến đếm i, j, k.

Không nên đặt tên biến quá dài, hay quá ngắn vì có thể làm rối chương trình hoặc cũng dẫn đến ý nghĩa biến mơ hồ(quá ngắn).

8.5. Biến static, enum

Tất cả các từ được viết hoa và phân cách bằng dấu gạch dưới (_).

Ví dụ:

  • static float PI = 3.14f
  • static int MIN_WIDTH = 4
enum ShapeType{
    SQUARE, CIRCLE, RECTANGLE
}

8.6. Biến final

Đối với biến final toàn cục: đặt tên biết giống như biến static. Tất cả các từ được viết hoa và phân cách bằng dấu gạch dưới (_).

Đối với biến fianl cục bộ: đặt tên biến giống như biến thông thường.

public class HinhTron {
// Biến toàn cục
final float PI = 3.14f;
<pre>public float tinhChuVi(int banKinh) {
    int duongKinh = banKinh * 2; // Biến cục bộ
    return duongKinh * PI;
}[/code]</pre>
}

8.7. Đặt tên package

Tên package: tất cả đều là chữ thường.

Ví dụ:

  • Đúng: com.example.deepspace
  • Sai: com.example.deepSpace hoặc com.example.deep_space

8.8. Viết một phương thức hiệu quả

Khi một đoạn code xuất hiện ở nhiều nơi trong chương trình ta gom các đoạn code đó thành một phương thức: Tiết kiệm thời gian bảo trì, sửa lỗi.

Khi trong một phương thức có các đoạn code xử lý phức tạp thì ta nên tách đoạn code phức tạp đó ra thành một phương thức riêng biệt: Dễ dàng theo dõi, debug.

Khai báo tham số truyền vào vừa đủ, tránh tình trạng khai báo tham số truyền vào nhưng không sử dụng.

Mỗi phương thức chỉ thực hiện một chức năng.

Kích thước của một phương thức: Nhiều thí nghiệm cho thấy một phương thức có khoảng từ 50 đến 150 dòng code là hợp lý. (Trích Steve McConnell, Chapter 7.4 – Code Complete, Second Edition. 2004).

Ví dụ:

Phương thức tinhVaHienThiDiem và tinhVaLuuDiemDiem:

  • Trùng lặp code tinhDiem, mỗi khi có thay đổi cách tính điểm phải đi sửa ở 2 nơi.
  • Một phương thức sử dụng cho 2 mục đích: nếu code tính điểm và code hiển thị hay lưu điểm phức tạp sẽ rất khó để bảo trì và đọc hiểu.

Nên tách ra các phương thức: tinhDiem, hienThiDiem, luuDiem

Phương thức getHoTen chỉ cần họ và tên, không sử dụng tham số chữ lót.

8.9. Sử dụng biến (variables)

Tránh tình trạng khai báo biến mà không sử dụng: nhiều trình biên dịch warning khi complie (Eclipse IDE).

Các lệnh if, while, for không nên lồng nhau hơn 3 bậc.

8.10. Import thư viện sử dụng

Chỉ import thư viện sử dụng cần thiết. Không sử dụng import tất cả.

Ví dụ: sử dụng import java.util.List; thay cho import java.util.*;

9. Tham khảo các chuẩn mã nguồn

Google Java Style Guide

Java_standards_v1.0_(NEAF)

JavaCodingConvention_Sun_1997