Tác giả bài viết này là một giảng viên.

Ông thường phải review code của sinh viên mình và tất nhiên có những lúc ông phát cáu với những dòng code "không thể thối hơn".

Code bẩn + sai ngữ nghĩa + bug = code thối

Thực ra ông không muốn cười nhạo hay chê bai ai cả, ông chỉ muốn mọi người học được bài học đáng nhớ từ những sai lầm này.

Và chúng ta hãy bắt đầu với một ví dụ rất.... kinh điển của code "thúi":

if(a<8&&b<8&&c<8)
a = 8;b=8;c=8;

Trước khi bạn đọc tiếp, hãy cố gắng liệt kê các lỗi mà đoạn code này mắc phải. Cố gắng liệt kê tất cả, từ lỗi về mặt ngữ nghĩa đến lỗi do vi phạm các quy tắc viết code sạch....

Trở thành một lập trình viên Java viết code sạch khi tham gia khoá học Lộ trình Java Spring Boot 7 tháng

Xong rồi, bạn xác định được bao nhiêu lỗi tất cả? Cùng phân tích nhé...

Điều đầu tiên mà ai cũng thấy đó là mật độ dầy đặc của các ký tự trong phần điều kiện của lệnh if. Ở đây có 3 điều kiện tất cả và cậu sinh viên này đã quên tách chúng ra với những dấu space.

Một điều không may ở đây là toán tử "and" - && và số 8 nhìn khá giống nhau. Nó làm dòng code trở nên "díu dít" và CỰC KÌ KHÓ ĐỌC.

Bài học bạn nhận được từ vấn đề này là gì? Hãy chú ý tới khoảng cách khi viết code.

if(a < 8 && b < 8 && c < 8)

Như thế này có vẻ dễ nhìn hơn rồi đó...

Vấn đề thứ 2 - magic number

Vấn đề này liên quan tới tính mạch lạc và trong sáng của code.

"Magic number" - những con số ma thuật - là khái niệm mà tác giả dùng để gọi những con số trong code mà chúng chỉ tồn tại ở đó nhưng không được define một cách rõ ràng rằng chúng biểu diễn cho một giá trị nào đó.

Đối với người review code hoặc teamate, những con số này gần như là "vô nghĩa" và đôi khi họ mất rất nhiều thời gian để có thể hiểu được ý nghĩa và vai trò của chúng.

Ở ví dụ này, ta thấy lệnh gán giá trị 3 biến a,b,c cho 8 tồn tại 2 vấn đề.

Thứ nhất, 8 trong trường hợp này trở thành "magic number". Khi bạn đọc qua đoạn code này, chắc chắn bạn không biết 8 đang biểu diễn cho cái gì (đối với tác giả thì đó là thời gian làm việc ban ngày của công nhân - 8 tiếng đồng hồ, bởi ông là người ra đề nên đương nhiên ông biết...).

Thứ hai, 8 được lặp lại 3 lần ở các phép gán. Như vậy, khi cần thay đổi giá trị 8 thành 7 hoặc tăng lên 12 chẳng hạn, ta sẽ phải đi dò từng vị trí mà 8 xuất hiện... Rất bất tiện và dễ phát sinh lỗi.

Để giải quyết, trong trường hợp này, ta khai báo một hằng số với tên đầy đủ....

final int WORK_HOURS = 8;

Như vậy, đến thời điểm này, 2 dòng code đầu bài sẽ được sửa thành:

if(a < WORK_HOURS && b < WORK_HOURS && c < WORK_HOURS)
a = WORK_HOURS;b = WORK_HOURS;c = WORK_HOURS;

Vấn đề thứ 3 - ngữ nghĩa

Ý đồ của đoạn code này là nếu cả 3 biến a,b,c nhỏ hơn WORK_HOURS thì sẽ gán giá trị của 3 biến này bằng WORK_HOURS.

Tuy nhiên, hãy nhìn vào phần thân lệnh if.... Bạn có hình dung được lệnh nào sẽ thực thi nếu điều kiện của if đúng và lệnh nào sẽ thực thi nếu điều kiện của if không đúng?

Đoạn code này được viết trong Java, và Java thì "không quan tâm" tới các khoảng trắng - space. Một lệnh trong Java kết thúc với dấu ; chứ không kết thúc bằng việc xuống dòng. Với cách viết code như trên thì phần thân lệnh if sẽ chỉ có 1 lệnh a = WORK_HOURS; . Điều này trái với ý đồ của người viết code. Hậu quả: 2 lệnh phía sau được thực thi cho dù điều kiện của lệnh if sai. Và tất nhiên kết quả cuối cùng sẽ không đúng như mong đợi.

Từ vấn đề thứ 3 này ta rút ra 2 bài học:

  1. Nếu thân lệnh if có nhiều hơn 2 lệnh, hãy sử dụng cặp dấu ngoặc nhọn {}
  2. Viết nhiều lệnh trong 1 dòng là một thói quen tồi

Cuối cùng, sau khi khắc phục tất cả các vấn đề, ta thu được đoạn code sau:

if(a < WORK_HOURS  &&  b < WORK_HOURS  &&  c < WORK_HOURS) {
    a = WORK_HOURS;
    b = WORK_HOURS;
    c = WORK_HOURS;
}

Mọi thứ có vẻ ổn rồi nhỉ?

Sự thật là chưa đâu... Hãy tiếp tục suy nghĩ nào. Tôi có 3 câu hỏi dành cho bạn:

  1. Hãy nhìn vào thân lệnh if, có 3 phép gán mà giá trị được gán chỉ là 1 hằng số. Liệu bạn có thể "dồn" 3 lệnh gán này thành 1 lệnh trên 1 dòng code không?
  2. Trong bài viết tôi có nhắc đến "magic number" để mô tả về các con số vô nghĩa... Vậy bạn thấy cách đặt tên biến là a,b,c như học trò của tôi thế nào? Khi nào nên đặt tên như thế và khi nào thì không?
  3. Điều gì xảy ra khi chỉ có 1 trong 3 biến a,b,c nhỏ hơn 8?

Techmaster via Dzone