Bàn về quy cách đặt tên (Naming Convention)

Có một câu trích dẫn mà chắc hẳn nhiều người đã từng nghe đến: “There are only two hard things in Computer Science: cache invalidation and naming things.” – Phil Karlton. Đại ý là trong lĩnh vực Khoa học máy tính: cache invalidation (vô hiệu cache) và đặt tên là 2 cản trở lớn nhất. Chúng ta thường nói về những khó khăn trong việc đặt tên nhưng lại ít nói về việc làm thế nào để cải thiện điều đó. Ngay cả khi phải sử dụng những cấu trúc từ phức tạp mà hợp lý để đặt tên, chứ đừng chọn những cái tên mà chỉ có bạn mới hiểu. Đặt tên là điều cần thiết để tạo nên những dòng code có chất lượng. Tên hợp lý có thể tạo nên một nền tảng code dễ tra cứu và làm việc. Những cái tên bất hợp lý làm code trở nên khó hiểu hoặc thậm chí tệ hơn là sinh ra lỗi.

Những ví dụ về việc đặt tên

Xem xét ví dụ sau:

function processData(data) {
  var result = JSON.parse(data);
  return result;
}

Dựa vào tên của hàm, tham số và biến trả về, chúng ta thấy rằng hàm processData nhận tham số là data và trả về kết quả result. Những cái tên này cung cấp lượng thông tin gần như vô giá trị đối với người đọc. Nếu bạn muốn thuận tiện khi viết code hoặc đang muốn duy trì sự linh động trước những thay đổi sau này thì cách viết như trên tạm chấp nhận được. Tuy nhiên, khi có lỗi xảy ra sau một khoảng thời gian nào đó, bạn có thể phải đọc lại đoạn code cũ cùng sự khó hiểu. Đây là lúc mà việc đặt tên trở nên có ý nghĩa khi đánh giá chất lượng của code. Dưới đây là một cách đặt tên có tính mô tả và cụ thể hơn của ví dụ trên:

function parseJson(string) {
  var jsonObject = JSON.parse(string);
  return jsonObject;
}

Công nghệ thông tin là một trong những lĩnh vực có nhiều chữ viết tắt nhất. Chính những chữ viết tắt này là chìa khóa để đặt tên hợp lý. Ví dụ FTP sẽ dễ đọc và dễ hiểu hơn File Transfer Protocal, mặc dù trong một vài trường hợp, người đọc có thể bỏ sót ý nghĩa của từ. Dưới đây là một ví dụ cho thấy từ viết tắt khiến lập trình viên viết code tiện lợi hơn nhưng lại cản trở những người khác đọc hoặc đóng góp vào nó.

function cts(con, ack) {
  if (con && ack) {
    return true;
  }
  else {
    return false;
  }
}

Việc lạm dụng các chữ viết tắt như trên gây ra không ít khó khăn cho những người đọc. Đây là phiên bản không chữ viết tắt của đoạn code trên:

function clearToSend(connectionExists, acknowledgementStatus) {
  if (connectionExists && acknowledgementStatus) {
    return true;
  }
  else {
    return false;
  }
}

Chúng ta sẽ tiếp tục tìm hiểu sang các ví dụ về HTML bởi nó có lẽ là một trong những ngôn ngữ có nhiều cái tên dài nhất.

<section class="new-promotion-parent">
  <img class="logo" src="small-square-logo-monochrome.png"/>
  <div class="get-your-coupon">
    <p>Get Your Coupon</p>
  </div>
</section>

Có thể suy đoán rằng từ new ở tên class new-promotion-parent trong ví dụ trên cập nhật thêm một số thuộc tính mới vào class promotion-parent nhưng vẫn giữ những thuộc tính còn lại. Từ khóa new không có ý nghĩa về mặt thời gian khi class có thể là mới lúc này nhưng lại là cũ khi để về sau. Cách tốt hơn cả là thêm một tên class tách biệt để mô tả những thay đổi mới. Ví dụ, nếu có một kiểu thiết kế phẳng được thêm mới, thì cái tên flat-design sẽ trở nên hợp lý. Ngoài ra, việc giữ lại tên class promotion-parent ban đầu cũng giúp chúng ta tái sử dụng một số thuộc tính.

Tương tự, logo cũng là một cái tên khá nhạy cảm. Không thể tránh khỏi khi có một logo thứ 2 xuất hiện ở đâu đó với tên class là alt-logo. Tiếp tục như vậy, chuỗi tên về logo gia tăng và trở nên bất cập. Hầu hết, những tài nguyên đều có nhiều biến thể như hình dạng, màu sắc , kích cỡ khác nhau. Do đó, small-square-logo-monochrome cũng không phải là một cái tên hợp lý khi mà việc thay đổi tên class bị phụ thuộc vào thuộc tính của ảnh. Cách tốt hơn có lẽ là đặt tên sao cho nó mô tả được vai trò của tài nguyên đó hơn là kiểu loại hay giao diện bề ngoài.

Cũng ở ví dụ trên, nội dung của thẻ div cũng được sử dụng để đặt tên cho class. Việc này khiến tên của thẻ HTML trở nên mập mờ và bất định khi mà nội dung của văn bản HTML thường xuyên thay đổi. Dưới đây là đoạn code HTML được viết lại với sự cân nhắc ở trên:

<section class="flat-design promotion-parent">
  <img class="promotion-branding-image" src="small-square-logo-monochrome.png"/>
  <div class="primary-promotion-text">
    <p>Get Your Coupon</p>
  </div>
</section>

Việc đặt tên còn có ý nghĩa trong cả các bảng cơ sở dữ liệu (CSDL). Xem xét ví dụ sau:

CREATE TABLE `book` (
  `id` int(12) NOT NULL,
  `title` varchar(50) NOT NULL,
  `author` varchar(50) NOT NULL,
  `type` bit(1) NOT NULL,
  `sort` int(12) NOT NULL,
  `order` varchar(25) NOT NULL,
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

Câu hỏi đặt ra là: type có nghĩa là gì trong ngữ cảnh của dữ liệu sách? Nó có phải để phân biệt sách thuộc thể loại viễn tưởng hay phi viễn tưởng? Hay để phân biệt là sách bìa cứng hay bìa mềm? Hoặc có thể là sách số hay sách giấy?

Cột sort cũng gây khó hiểu khi không phân biệt được nó thể hiện cho việc sắp xếp theo tiêu chí nào. Tăng dần hay giảm dần? Sắp xếp theo cột nào? Hay nó chỉ quyết định xem việc sắp xếp có được cho phép hay không? Hoặc việc sắp xếp theo một thứ tự luân phiên nào đó có được diễn ra?

Tương tự với cột order thì ngoài sự mập mờ, nó cũng là từ khóa reserved của MySQL và nhiều ngôn ngữ khác. Bạn có thể sử dụng dấu backtick (`) cho MySQL nhưng chắc chắn tốt hơn hết là tránh việc sử dụng các từ reserved đồng thời. Bảng CSDL trên có thể được viết lại theo một cách cụ thể hơn như sau:

CREATE TABLE `book` (
  `id` int(12) NOT NULL,
  `title` varchar(50) NOT NULL,
  `author` varchar(50) NOT NULL,
  `cover_type` bit(1) NOT NULL,
  `sort_order` int(12) NOT NULL,
  `purchase_order_number` varchar(25) NOT NULL,
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

Quy cách đặt tên

Xét ví dụ sau:

if (oldmanshaven) {
  return true;
}

Câu điều kiện ở trên có thể gây nhầm lẫn giữa Old Mans Haven và Old Man Shaven. PascalCase, camelCase, snake_case và kebab-case là những lựa chọn tối ưu nhất khi đặt tên. Hãy sử dụng chúng sao cho phù hợp. Đoạn code sau sử dụng snake_case khiến đoạn code trở nên rõ ràng hơn:

if (old_man_shaven) {
  return true;
}

Một ví dụ khác:

if (isNaN(number)) {
  alert('not a number')
}
else if (number > 50) {
  alert('number too large')
}
else if (number < 10) {
  alert('number too small')
}
else {
  // code here
}

Đoạn code trên tránh việc đặt tên bằng cách hạn chế sử dụng hàm, hạn chế các phép gán và tận dụng biến có sẵn. Tuy nhiên, cách viết như trên không thể hiện được tính trừu tượng. Chúng ta có thể viết lại như sau:

function validateNumber(number) {
  var maximumValue = 50;
  var minimumValue = 10;
  if (isNaN(number)) {
    alert('not a number')
    return false;
  }
  if (number > maximumValue) {
    alert('number too large')
    return false;
  }
  if (number < minimumValue) {
    alert('number too small')
    return false;
  }
}

if (validateNumber(number)) {
  // code here
}

Một vài lưu ý

Đặt tên được ví như một nghệ thuật, không phải là khoa học. Có một vài khía cạnh ngoài lề cần được cân nhắc khi đánh giá việc đặt tên là tốt hay xấu.

Ngữ cảnh

Ngữ cảnh có thể cho thấy những quy tắc chung hơn là ngữ nghĩa. Ví dụ, “item” là một cái tên mập mờ nhưng trong ngữ cảnh của hàm getCustomerSalesOrder(), nó có thể được hiểu là sản phẩm đã được mua. Một hàm mà tập trung vào một ngữ cảnh cụ thể sẽ tránh được việc đặt tên rườm rà. Tuy nhiên, cũng có trường hợp ngữ cảnh không cố định khi hàm phát triển thêm hoặc refactored. Do đó, việc đặt tên vẫn là cách để thể hiện ngữ nghĩa một cách dài hạn.

Comments

Comments là thứ quan trọng để code trở nên dễ đọc nhưng chúng không thể đảm nhiệm một mình được. Comments nên chọn những nội dung mà tên bỏ sót, thể hiện chi tiết những điều mà không thể hiểu hết được từ tên.

/* This refers to a product that was purchased and relates to the customer-sales-order class. */
.product-item {
  display: block;
  text-transform: uppercase;
  width: 100vw;
}

Thời gian đọc

Tên càng dài thì càng mất nhiều thời gian đọc. Đặc biệt là khi truy cập sâu vào một mảng như sau:

$order_details['customer']['ship_to_address']['default']['street_address']['line_1']

Mặc dù khá rườm rà nhưng không thể đánh giá đó là một cái tên không tốt vì nó rất rõ ràng và cụ thể.

Tên xuất hiện ở mọi nơi trong code

Hầu hết ký tự trong code không phải là các dấu ngoặc hay cú pháp, mà là tên. Nó có thể là tên biến, tên hàm, tên thẻ hay thuộc tính HTML, tên cột hay tên bảng CSDL hoặc bất cứ thứ gì ta muốn trừu tượng hóa.

Việc đặt tên có thể tốn nhiều thời gian khi bạn phải xử lý một thứ gì đó mà khó để khái niệm hóa. Tuy nhiên, điều này là rất đáng làm khi muốn nâng cao chất lượng của code.

Lược dịch:

Cory Long, Working Towards Better Naming, https://css-tricks.com/working-towards-better-naming/