6. Chính xác, Đơn giản, Rõ Ràng

Estimated reading: 7 minutes 301 views

Tóm tắt

KISS (Keep It Simple Software): Chính xác quan trọng hơn tốc độ. Đơn giản tốt hơn phức tạp. Rõ ràng tốt hơn cầu kỳ. Ổn định tốt hơn bấp bênh (xem thêm các mục 83 và 99).

Thảo luận

Khó có thể đánh giá hết giá trị của các thiết kế đơn giản và mã nguồn rõ ràng. Người bảo trì mã code của bạn sẽ cảm ơn bạn vì đã làm cho nó dễ hiểu — và thường thì người đó chính là bạn trong tương lai, người đang cố gắng nhớ lại suy nghĩ của mình từ sáu tháng trước. Vì vậy, những lời khuyên kinh điển như sau luôn có giá trị:

“Các chương trình phải được viết để cho con người đọc, và chỉ nhân tiện để cho máy tính thực thi.”
— Harold Abelson và Gerald Jay Sussman

“Hãy viết chương trình dành cho con người đầu tiên, thứ hai mới cho máy tính.”
— Steve McConnell

“Những thành phần rẻ nhất, nhanh nhất và đáng tin cậy nhất của một hệ thống máy tính là những thành phần không tồn tại.”
— Gordon Bell

“Những thành phần không tồn tại này cũng là những thành phần chính xác nhất (chúng không bao giờ mắc lỗi), an toàn nhất (chúng không thể bị tấn công), và dễ thiết kế, viết tài liệu, kiểm thử, cũng như bảo trì nhất. Tầm quan trọng của thiết kế đơn giản không thể được nhấn mạnh quá mức.”
— Jon Bentley

Nhiều mục trong chuỗi bài này đều nhắm đến các thiết kế và mã nguồn dễ thay đổi, nhấn mạnh thêm sự rõ ràng là phẩm chất mong muốn nhất của các chương trình dễ bảo trì và dễ tái cấu trúc. Những gì bạn không thể hiểu rõ thì bạn cũng không thể tự tin thay đổi.

Một trong những vấn đề căng thẳng phổ biến nhất trong lĩnh vực này là sự giằng co giữa sự rõ ràng của mã code và việc tối ưu hóa (xem các mục 7, 8 và 9). “Khi” (chứ không phải “nếu”) bạn đối mặt với cám dỗ tối ưu hóa sớm nhằm nâng cao hiệu suất mà làm giảm tính rõ ràng của mã code, hãy nhớ đến quan điểm trong mục 8: “Sẽ dễ dàng hơn nhiều để làm cho một chương trình đúng đắn chạy nhanh hơn là làm cho một chương trình nhanh chạy đúng đắn.”

Hãy tránh những “góc khuất” của ngôn ngữ. Sử dụng những kỹ thuật đơn giản nhất nhưng vẫn hiệu quả.

Ví dụ

Ví dụ 1: Tránh nạp chồng toán tử một cách không cần thiết hoặc cầu kỳ

Một thư viện GUI đã buộc người dùng viết w + c; để thêm control con c vào một widget w một cách lạ lùng (Xem mục 26.)

Ví dụ 2: Ưu tiên truyền các biến được đặt tên thay vì các giá trị tạm thời làm tham số của hàm tạo (constructor)

Điều này giúp tránh được các mơ hồ trong khai báo và thường làm rõ mục đích của mã, từ đó giúp dễ bảo trì hơn. Đồng thời, nó cũng thường an toàn hơn (xem các mục 13 và 31). Cụ thể:

  • Tránh mơ hồ trong khai báo: Khi trình biên dịch gặp các biểu thức phức tạp hoặc giá trị tạm thời, nó có thể không giải quyết chính xác được kiểu dữ liệu mong muốn
  • Tăng tính rõ ràng: Sử dụng các biến có tên giúp mã dễ đọc và dễ hiểu hơn
  • Dễ bảo trì và an toàn hơn: Nếu cần thay đổi giá trị, bạn chỉ cần chỉnh sửa biến thay vì tìm kiếm trong toàn bộ mã nguồn
				
					// Đoạn mã không sử dụng biến được đặt tên, mà sử dụng giá trị tạm
// Nếu giá trị truyền vào dài hoặc phức tạp, việc hiểu ý nghĩa của chúng sẽ khó khăn
// Khi cần chỉnh sửa các giá trị, bạn phải thay đổi toàn bộ biểu thức
// Dễ dẫn đến lỗi khi khai báo với nhiều kiểu dữ liệu khác nhau

#include <iostream>
#include <string>

class Person {
public:
    Person(const std::string& name, int age) : name_(name), age_(age) {}
    void print() const {
        std::cout << "Name: " << name_ << ", Age: " << age_ << '\n';
    }
private:
    std::string name_;
    int age_;
};

int main() {
    // Truyền trực tiếp các giá trị tạm thời (temporary values)
    Person person("Alice", 25); // Rõ ràng nhưng khó thay đổi
    person.print();

    // Truyền các biểu thức phức tạp
    Person anotherPerson(std::string("Bob") + " Smith", 20 + 5);
    anotherPerson.print();
    
    return 0;
}
				
			
				
					// Đoạn mã sử dụng biến được đặt tên
// Nếu cần chỉnh sửa giá trị, bạn chỉ cần thay đổi tại vị trí khai báo biến, không cần sửa trong toàn bộ constructor
// Dễ kiểm tra và bảo trì hơn khi mã phát triển phức tạp

#include <iostream>
#include <string>

class Person {
public:
    Person(const std::string& name, int age) : name_(name), age_(age) {}
    void print() const {
        std::cout << "Name: " << name_ << ", Age: " << age_ << '\n';
    }
private:
    std::string name_;
    int age_;
};

int main() {
    // Sử dụng các biến có tên để lưu giá trị
    std::string name = "Alice";
    int age = 25;

    Person person(name, age);
    person.print();

    // Với các giá trị phức tạp, chia nhỏ để tăng tính rõ ràng
    std::string fullName = "Bob Smith";
    int calculatedAge = 20 + 5;

    Person anotherPerson(fullName, calculatedAge);
    anotherPerson.print();
    
    return 0;
}
				
			

Tham khảo

[Abelson96] • [BentleyOO] §4 • [Cargill92] pp. 91-93 • [Cline99] §3.05-06 • [Constantine95] §29 • [Keffer95] p. 17 • [Lakos96] §9.1, §10.2.4 • [McConnell93] • [MeyersOl] §47 • [StroustrupOO] §1.7, §2.1, §6.2.3, §23.4.2, §23.4.3.2 • [SutterOO] §40-41, §46 • [SutterO4] §29

Link

Leave a Comment

Chia sẻ:

6. Chính xác, Đơn giản, Rõ Ràng

Or copy link

CONTENTS