Với một coder, viết code nhanh, đúng, chưa đủ mà bạn còn phải viết đẹp và dễ đọc nữa, vì nó sẽ giúp code dễ bảo trì hơn. Trong công việc hàng ngày, đôi khi việc tìm và sửa lỗi còn mất thời gian hơn viết mới nữa, vì bạn có thể sẽ phải đọc lại những đoạn code do người khác viết, hoặc thậm chí do chính bạn viết, từ trước đó rất lâu (thậm chí có thể trước khi bạn biết dùng máy tính :D).

Hãy thử đọc lại một chương trình bạn viết khi mới vào nghề xem, nếu nó cũ hơn 3 năm, tôi tin chắc 99% bạn sẽ thấy nó rất … buồn cười :D.
Lời khuyên đầu tiên của tôi là: Ngay từ ngày đầu tiên, hãy học cách viết code rõ ràng, sáng sủa, kể cả khi bạn biết chắc sẽ không ai đọc nó. Hãy biến nó thành thói quen và phải cảm thấy khó chịu khi nhìn vào một một đoạn “dirty code”.
Trong bài này, tôi sẽ nói qua những dấu hiệu cần tránh, giúp chương trình của bạn sẽ đọc, dễ bảo trì hơn. Có rất nhiều dấu hiệu như vậy, do đó tôi sẽ chia chúng ra nhiều bài ngắn giúp bạn dễ theo dõi.
Các phương thức quá dài (Long method)
Các phương thức quá dài làm tăng độ phức tạp, khó test và debug. Thông thường khi viết, bạn sẽ có xu hướng viết thêm vào một phương thức đã có thay vì tạo một cái mới, nhất là với những thay đổi nhỏ (vài dòng), dần dần sau một thời gian, đoạn code của bạn trở nên khó đọc. Bản thân các phương thức dài cũng có tiềm năng là nơi chứa các đoạn code thừa.
Cách sửa đầu tiên là chuyển bớt code sang một phương thức mới, ta gọi phương pháp này là “Extract method“. Ví dụ:
void printInvoice(Invoice invoice)
{
Console.WriteLine($"Invoice: {invoice.Number}");
Console.WriteLine($"Customer: {invoice.CustomerName}");
foreach (var line in invoice.Lines)
{
Console.WriteLine($"{line.ProductName} x {line.Quantity} {line.Total}");
}
Console.WriteLine($"Sub-Total: {invoice.SubTotal}");
Console.WriteLine($"Tax: {invoice.Tax}");
Console.WriteLine($"Total: {invoice.Total}");
}
Đoạn code trên có thể sửa lại thành:
void printInvoice(Invoice invoice)
{
printInvoiceHeader(invoice);
printInvoiceDetails(invoice);
printInvoiceFooter(invoice);
}
void printInvoiceHeader(Invoice invoice)
{
Console.WriteLine($"Invoice: {invoice.Number}");
Console.WriteLine($"Customer: {invoice.CustomerName}");
}
void printInvoiceDetails(Invoice invoice)
{
foreach (var line in invoice.Lines)
{
Console.WriteLine($"{line.ProductName} x {line.Quantity} {line.Total}");
}
}
void printInvoiceFooter(Invoice invoice)
{
Console.WriteLine($"Sub-Total: {invoice.SubTotal}");
Console.WriteLine($"Tax: {invoice.Tax}");
Console.WriteLine($"Total: {invoice.Total}");
}
Sau khi sửa lại, các phương thức sẽ ngắn gọn, dễ đọc, nếu gặp vấn đề ta cũng dễ tìm ra hơn. Việc tách ra như vậy cũng giúp chúng ta dễ dùng lại các đoạn code hơn.
Khi chuyển các đoạn code trong phương thức đầu tiên vào các phương thức nhỏ hơn, nếu có các biến chúng cũng sẽ được chuyển luôn vào phương thức mới, nếu chúng được khai báo ngoài phạm vi đó thì ta sẽ biến chúng thành các tham số và truyền vào khi gọi hàm.
Các khối lặp hoặc điều kiện là những ứng viên tốt cho việc chuyển thành một method mới.
Bạn đừng sợ việc tách ra như vậy sẽ khiến chương trình chạy chậm hơn, có lẽ trong hầu hết trường hợp bạn sẽ không thể nhận thấy sự khác biệt đó, một lời gọi hàm cũng sẽ chỉ tương đương một lệnh JUMP mà chúng ta vẫn dùng trong các khối lệnh thôi.
Các lớp quá lớn (Large class)
Tương tự với Long method, Large class cũng làm các chương trình trở nên khó đọc, khó bảo trì.
Nếu nhận thấy một class quá lớn, bạn có thể dùng những phương pháp sau để refactor code:
Extract class: gom các các thành phần vào các lớp mới nếu chúng phục vụ cho những mục đích khác nhau.
class Invoice
{
public string InvoiceNumber { get; set; }
public DateTime InvoiceDate { get; set; }
public string CustomerName { get; set; }
public string CustomerAddress { get; set; }
public string CustomerPhone { get; set; }
}
Với ví dụ trên, bạn hoàn toàn có thể chuyển thông tin khách hàng vào một lớp mới: Customer hoặc InvoiceCustomer chẳng hạn.
Khi chuyển sang một class mới, hãy cố gắng tạo một lớp không phụ thuộc vào lớp cũ, như vậy bạn sẽ dễ dàng dùng lại code hơn. Trong lớp mới, bạn cũng nên cân nhắc mức độ che dấu các thành phần mới chuyển qua và áp dụng các mức độ phù hợp (public/private…).