[Code sao cho chuẩn] – Phần 2: Đặt tên biến – việc đơn giản nhưng bạn đã làm đúng?

        Không quá khi nói rằng: đặt tên biến là một trong những việc làm mất thời gian nhất khi viết code. Vậy làm thế nào để cải thiện việc này? Chúng ta nên đặt tên biến như thế nào cho phù hợp?

       Bạn đã từng trải qua việc vò đầu bứt tóc suy nghĩ cả buổi vẫn không tìm ra 1 cái tên hợp lí cho 1 cái biến vớ vẩn nào đó – khi mà bạn đã đặt 10 cái tên biến khác trong phạm vi đó, hay bạn đã trải qua việc mất cả ngày trời để debug những lỗi tưởng chừng bự như con voi trong khi nó đơn giản chỉ là việc dùng sai hàm, bởi bạn đã nhầm lẫn nội dung xử lí của nó với cái tên chẳng mấy ăn nhập. Vậy mới thấy tên biến đôi khi ảnh hưởng nhiều tới việc viết code như thế nào.

         Cũng giống như việc đặt tên các đối tượng khác trong đời sống hằng ngày, tên không được quá phức tạp và dài để khiến nó trở nên khó nhớ, nhưng cũng không được quá đơn giản để khiến nó trở nên mơ hồ và không còn giữ được tính dễ nhận biết. Để làm được điều này, chúng ta nên dựa vào 2 tiêu chí sau đây:

- Tiêu chí thứ nhất: Tên phải thể hiện được ý nghĩa và vai trò của nó. 
- Tiêu chí thứ hai: Tên phải rõ ràng và tránh bị hiểu lầm.

        Như mình đã nói, tiêu chí code sao cho dễ hiểu đóng vai trò rất quan trọng. Do vậy chúng ta sẽ dựa trên 2 tiêu chí này để phân tích và đưa ra những quy tắc đặt tên tối ưu và dễ hiểu nhất.

Tên phải thể hiện được ý nghĩa và vai trò của nó.

packing-info-into-names
Tên phải thể hiện được nhiệm vụ của nó (Nguồn ảnh: The art of readable code)

          Có lẽ ai trong chúng ta đều hiểu được tiêu chí này, và rằng cái tên mà chúng ta sẽ đặt cho biến phải thể hiện được ý nghĩa và nhiệm vụ của biến. Vậy hãy lưu ý tới những tiêu chí sau đây:

1. Tránh dùng những từ nhiều nghĩa, hãy dùng những từ có nghĩa cụ thể

     Có những từ mà bản thân nó hàm chứa ý nghĩa không rõ ràng; kiểu như “do”, “prepare”, “get” ..v.v. Nếu chúng ta đặt tên hàm kiểu như “prepareLayout()” hoặc “getLayout()” thì rất khó để truyền tải được ý nghĩa thật sự của nó là gì.

        Giả sử bạn muốn tải một layout từ internet về để xử lí, thì tốt hơn là bạn nên đặt tên kiểu như downloadLayout(), nếu muốn xoá trắng layout trước khi xử lí thì cái tên clearLayout() sẽ hợp lí hơn nhiều.

          Một ví dụ khác, giả sử bạn khai báo một lớp xử lí như sau:

class BalanceTree{
    int size;
    …
}

        Vậy bạn muốn truyền tải gì qua biến size? Nếu bạn muốn nói về độ cao của cây, hãy dùng từ height, nếu muốn nói tới số lượng nodes thì hãy dùng numNode … Tóm lại là bạn nên tránh dùng những từ có ý nghĩa chung chung mà thay vào đó là dùng những từ có nghĩa cụ thể hơn. Điểm lưu ý tiếp theo là:

2. Chỉ rõ hành vi chứ không phải ý định

       Giả sử bạn viết một hàm nhận tham số đầu vào để điều khiển việc có xuất log vào file hay không, và bạn đặt tên cho tham số đó là “debug”. Bạn quy định nếu debug = TRUE thì xuất log, ngược lại thì không:

function processABC(int param1, int param2, bool debug) {
   . . .
   if(debug) {
      //export log to file
   }
}

       Thoạt nhìn thì có vẻ như mọi thứ đều ổn, cho tới khi một người khác tiếp nhận code của bạn. Liệu họ sẽ đủ thời gian để hiểu được “debug” thực sự là làm gì? Là ghi log, là kích hoạt tham số ẩn hay đơn giản là dừng chương trình khi có bất kì warning nào xảy ra? Nếu mục tiêu của bạn đơn giản là muốn ghi log, chẳng phải tên biến exportLog rõ ràng hơn nhiều so với debug hay sao?

      Bạn sẽ tránh được nhiều lỗi và tiết kiệm nhiều thời gian cho người khác chỉ với một thay đổi rất nhỏ này.

3. Chèn thêm những thông tin quan trọng vào tên biến

       Đôi khi thể hiện được mục đích của biến thôi là chưa đủ, chúng ta còn cần có những ràng buộc thêm cho biến. Với những tình huống này, chúng ta nên đính kèm những ràng buộc này vào tên của chúng.

       Ví dụ, liên quan tới kiểu dữ liệu của biến. Giả sử chúng ta có đoạn mã xử lí để tính khoảng thời gian như sau:

var start = (new Date()).getTime();
var elapsed = (new Date()).getTime() - start;

WriteToScreen( “The processing time is: ” + elapsed + “seconds”);

        Có điều gì không đúng ở đây không?

      Câu trả lời nằm ở chỗ hàm getTimet() trả về đơn vị là mili giây trong khi ta đang muốn xuất ra thông tin ở đơn vị giây. Đôi khi đơn vị tính của giá trị đóng vai trò quan trọng trong các xử lí của chúng ta, có thể người lập trình hiểu rõ được giá trị trả về của hàm getTime() là mili giây, tuy nhiên có thể vì vội vàng xử lí hay điều gì đó mà họ quên mất điều này ở kết quả tính cuối cùng.

          Chúng ta có thể tránh được việc quên này đơn giản chỉ bằng việc chỉ rõ đơn vị tính của biến. Chúng ta sẽ dùng “start_ms” thay cho “start”, dùng “elapsed_ms” thay cho “elapsed”. Như vậy code sẽ tường minh và rõ ràng hơn:

var start_ms = (new Date()).getTime();
var elapsed_ms = (new Date()).getTime() - start_ms;

WriteToScreen( “The processing time is: ” + elapsed_ms / 1000 + “seconds”);

         Tương tự với ý tưởng trên, những trường hợp mà chúng ta cũng nên thể hiện ở tên biến như: trạng thái, phạm vi truy cập, …

4. Biến tạm - hãy đặt tên rõ ràng

        Có một vấn đề mà chúng ta rất hay gặp phải đó là: đặt tên biến tạm. Hãy thử xem xét các biến tạm hay dùng trong vòng lặp như sau:

for (int i = 0; i < clubs.size(); i++)
    for (int j = 0; j < clubs[i].members.size(); j++)
        for (int k = 0; k < users.size(); k++)
            if (clubs[i].members[k] == users[j])
                cout << "user[" << j << "] is in club[" << i << "]" << endl;

      Hầu hết mọi người đều dùng các tên đơn giản như “i”, “j”, “k” để đặt tên biến lặp, điều này không có gì sai cả, tuy nhiên khi có nhiều vòng lặp xử lí cùng 1 lúc, thì có vẻ mọi việc dần trở nên mất kiểm soát. Developer sẽ rất khó để phát hiện các lỗi liên quan tới chỉ số của biến lặp. Do vậy, sẽ tốt hơn nếu ta đính kèm thêm thông tin vào biến lặp để nó rõ nghĩa hơn:

//Dòng code chưa tốt
if (clubs[i].members[k] == users[j])

//Có thể sửa lại như sau:
if (clubs[club_i].members[mem_k] == users[user_j])

//Hoặc sửa thành
if (clubs[ci].members[mk] == users[uj])

       Chỉ với thao tác đơn giản là chỉnh sửa tên của biến, chúng ta đã truyền tải rõ hơn ý định logic của mình tới những người phát triển khác. Một việc nhỏ mà lợi ích không hề nhỏ phải không nào?

2. Tên phải rõ ràng và tránh bị hiểu lầm.

misunderstood.JPG
Cắt bên nào? (Nguồn ảnh: The art of readable code)

        Với những tiêu chí được đề cập ở trên, chúng ta đã có thêm rất nhiều thông tin vào tên biến, làm cho chúng trở nên dễ hiểu hơn. Ở phần này chúng ta sẽ nói về khía cạnh khác: cần tránh các trường hợp người đọc hiểu lầm ý nghĩa của chúng.

        Trong một vài tình huống, việc người đọc code hiểu sai ý của người viết code không phải vì bản thân cái tên biến khó hiểu hay mơ hồ, mà đơn giản chỉ vì người đọc đã có những hình dung khác trước khi họ đọc code. Lấy ví dụ:

class Student{
    String name;
    int subjects_score[];

    //Compute and return the student’s avarage score.
    int getAverageScore(){
         // Iterate through array subjects_score and return (total score / num_subjects)
    }
}

         Đoạn code trên đáp ứng tốt các tiêu chí mà chúng ta đã đưa ra ở phần trên, thế nhưng nó sẽ gặp phải một vấn đề: Hầu hết các lập trình viên đều dùng từ “get” để đặt tên cho hàm có hành động “lấy và trả về một thuộc tính nội tại của lớp”, chỉ đơn giản là “lấy ra” mà không phải tốn chi phí tính toán. Việc chúng ta dùng từ “get” đặt tên cho một hàm có xử lí tính toán dường như đi ngược lại với thói quen của những developer khác, nếu người khác tái sử dụng lại hàm tính điểm trung bình này, rất có thể họ sẽ dùng nó theo một cách có thể ảnh hưởng tới hiệu năng của chương trình, làm chương trình chạy chậm hơn.

         Mặc dù không vi phạm quy tắc gì đi nữa thì chúng ta cũng nên tránh điều này. Sẽ tốt hơn nếu chúng ta dùng computeAvarageScore() thay cho getAvarageScore(), chúng ta sẽ chỉ nên dùng “get” để đặt tên cho một hàm không cần tính toán, ví dụ như getStudentName(). Bằng cách thay đổi tên hàm như trên, chúng ta sẽ giúp các lập trình viên khác hiểu chính xác hơn và tránh được các lỗi hiệu suất (performance) tiềm năng có thể xảy ra.

Tóm lại thì chúng ta nên đặt tên biến như thế nào?

       Tổng kết lại, việc đặt tên biến tưởng chừng đơn giản nhưng chúng ta cũng cần để ý những vấn đề tiềm ẩn có thể xảy ra trong tương lai, các tiêu chí cần nhớ để đặt tên biến có thể được tóm gọn lại như sau:

  • Tiêu chí 1: Tên phải thể hiện được đầy đủ ý nghĩa và vai trò của nó.
    • Tránh dùng từ nhiều nghĩa, hãy dùng những từ có nghĩa cụ thể.
    • Chỉ rõ hành vi thay vì ý định.
    • Chèn thêm những thông tin quan trọng vào tên.
  • Tiêu chí 2: Tên phải rõ ràng và tránh bị hiểu lầm.

          Chỉ thế thôi. Chúc vui & enjoy coding!

Tham khảo:
Sách: Clean Code: A Handbook of Agile Software Craftsmanship
Sách: The art of readable code

 

8 thoughts on “[Code sao cho chuẩn] – Phần 2: Đặt tên biến – việc đơn giản nhưng bạn đã làm đúng?

  1. Mih thường lười suy nghĩ tên biến nên đặt tên biến rất sida, bữa sau đọc lại chả bít mih đã viết j lun :v :v
    Thank u tác giả , ví dụ rất cụ thể và dễ hiểu 🙂

    Like

  2. Pingback: Series viết code sao cho chuẩn: Bài 3 – Bàn về comment code, vô kiếm hay hữu kiếm đây? – Webbynat

  3. Mình làm cho một công ty outsource nên hầu như ngày nào cũng phải đọc source code do người khác viết. Và các trường hợp đặt tên biến chung chung và mơ hồ khiến mình mất nhiều thời gian để dò dẫm theo từng dòng xử lý mới hiểu được các biến đó sử dụng để làm gì.
    Vậy mới thấy việc đặt tên biến tưởng chừng đơn giản nhưng lại quan trọng như thế nào. Việc đặt tên biến tùy tiện không những khiến việc đọc hiểu code trở nên khó khăn cho người khác, mà biết đâu đấy, là cho bản thân người code khi đọc lại code của chính mình sau vài tháng xa cách. 😀
    Bài viết rất bổ ích. Phần tổng kết cuối bài giúp việc nắm bắt và ghi nhớ những ý chính dễ dàng hơn rất nhiều. 🙂
    Mong sẽ sớm có những bài chia sẻ tiếp theo về cách viết code rõ ràng, dễ hiểu.
    Cảm ơn tác giả đã chia sẻ. 😀

    Like

  4. Pingback: [Giới thiệu sách] The art of readable code – Cái tên đã nói lên tất cả – Webbynat

  5. Pingback: [Code sao cho chuẩn] – Bài 1: Hãy bắt đầu nghĩ tới việc viết code đẹp hơn và dễ hiểu hơn. – Những dòng code vui

  6. Pingback: [Code sao cho chuẩn] Bài 3 – Bàn về comment code. – Những dòng code vui

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s