Clean Code P1

1. Clean code là gì?

Chắc hẳn các bạn cũng đã từng gặp trường hợp đọc code của người khác và thốt lên rằng "Viết cái quái gì thế này?", "Code gì chuối thế này?", "WTF"... đó là biểu hiện của code không sạch.

Clean code dịch ra tiếng Việt có nghĩa là code sạch. Thực ra rất khó để có thể định nghĩa chính xác thế nào là code sạch bởi vì mang tính cảm tính khá cao, giống như người khác bảo gu bạn mặn nhưng mà bạn thì không thấy vậy. Ta có thể định nghĩa clean code là code dễ đọc, dễ hiểu, tuân theo một quy chuẩn nào đó, dễ bảo trì và dễ thay đổi.

Một số tiêu chí để đánh giá clean code:

  • Cách trình bày code: cách căn lề, sử dụng tab, space… sao cho dễ đọc, dễ nhìn
  • Tên hàm, biến phải có ý nghĩa, theo một chuẩn coding convension
  • Hạn chế comment nhưng độc vô phải dễ hiểu
  • Khả năng dễ mở rộng, thay đổi của code

"Đơn vị duy nhất để đánh giá chất lượng code đó là: WTF/Minute"

2. Một số nguyên tắc cần tuân theo

2.1 Đặt tên có ý nghĩa

2.1.1 Đặt tên có ý nghĩa

Tên hàm, biến phải có ý nghĩa, thể hiện rõ vai trò và mục đích.

public int Get(int a) {
    Product product = _dbContext.Products.Find(x => x.Id = a);
    return product.Price;
}

Theo ví dụ trên là hàm nhân vào id của sản phẩm và trả về giá của sản phẩm đó. Nếu một người nào đó đọc vào thì phải đọc hiểu code mới có thể hiểu được hàm này muốn làm gì.
Ta có thể sửa lại như sau

public int GetProductPriceById(int productId) {
    Product product = _dbContext.Products.Find(x => x.Id = productId);
    return product.Price;
}

Sau khi sửa người đọc dễ dàng hiểu được hàm này muốn làm gì và cần tham số nào

2.1.2 Đặt tên dễ tìm kiếm

Nên đặt tên dễ tìm kiếm để người khác có thể đễ dàng tìm, đọc và hiểu code

2.1.3 Các hằng nên được khai báo thay vì sử dụng trực tiếp

Bad

for (int i = 0; i < 5; i++) {
    
}

Good

public const int WORK_DAYS_PER_WEEK = 5;

for (int i = 0; i < WORK_DAYS_PER_WEEK; i++) {
    
}

2.2 Làm cho Function clean

2.2.1 Function chỉ nên thực hiện một chức năng duy nhất

Một hàm chỉ nên thực hiện một chức năng duy nhất

Bad

public Task CreateTask(bool isEmptyTask) {
    if (isEmptyTask) {
        // Create empty task
    } else {
        // Create none empty task
    }
}

Good

public Task CreateEmptyTask() {
    // Body
}
public Task CreateNonEmptyTask() {
    // Body
}

2.2.2 Function nên tinh gọn

Hàm nên tinh gọn, số lượng code mỗi dòng và số dòng code tối đa của hàm nên tuân theo một chuẩn nhất định

2.3 Objects and Data Structures

2.3.1 Ẩn cấu trúc bên trong object

Các member nên private hoặc protected, sử dụng các function để thay đổi giá trị của các member này. VD:
Bad

public class Account {
    public int balance;
    
    public Account(int balance) {
        this.balance = balance;
    }
}

Account account = new Account(1000000);
// Widthdraw
account.balance -= 200000;
// Deposit
account.balance += 200000;

Good

public class Account {
    private int _balance;
    public int Balance {
        get {
            return _balance;
        }
    }
    
    public Account(int balance) {
        _balance = balance;
    }
    
    public void Widthraw(int amount) {
        if (amount > _balance) {
            throw new Exception("Invalid amount");
        }
        _balance -= amount;
    }
    
    public void Deposit(int amount) {
        _balance += amount;
    }
}

Account account = new Account(1000000);
// Widthdraw
account.Widthraw(200000);
// Deposit
account.Deposit(200000);

2.4 Comments

  • Cách tốt nhất để comment đó là sử dụng chính tên biến và tên hàm
  • Chỉ sử dụng comment để giải thích, làm rõ hơn hoặc cảnh báo người đọc

Kỳ sau chúng ta sẽ đi vào chi tiết clean code trong .net
To be continued...