# 91: Nguyên tắc WET làm giảm nghẽn cổ chai

Điều quan trọng của nguyên tắc DRY (opens new window) là thực hiện hoá ý tưởng mỗi kiến thức nhất định trong chương trình chỉ nên được thể hiện bởi một thứ. Nói cách khác, kiến thức ấy chỉ nên được cài đặt một lần duy nhất. Từ trái nghĩa của nó chính là WET. Code của chúng ta WET khi chúng ta thực hiện hoá một kiến thức bằng nhiều sự cài đặt khác nhau. DRY và WET có sự ảnh hưởng vô cùng lớn đến hiệu năng được thể hiện bằng các số liệu cụ thể.

Hãy bắt đầu bằng việc xét một tính năng trên hệ thống của chúng ta, xem X, là cổ chai CPU (Các luồng xử lý hợp lại thành 1 số lượng “luồng” chính đi vào CPU để xử lý). Tiếp theo, giả sử X tiêu thụ 30% hiệu năng của CPU. Bây giờ hãy tưởng tượng X có mười cài đặt khác nhau, trung bình thì mỗi cài đặt này tiêu thụ hết 3%. Ở mức độ tiêu thụ hiệu năng này thì chúng ta có thể không cần quan tâm đến nó nếu như bạn đang tìm giải pháp nhanh chóng, giống như là chúng ta đã quên mất sự ùn tắc mà nó tạo ra.

Tuy nhiên, giả sử rằng chúng ta bằng một cách nào đó phát hiện ra sự ùn tắc đó. Và bây giờ chúng ta đối mặt với vấn đề tìm kiếm và sửa chữa từng thiết lập ấy. Với WET chúng ta có đến mười thiết lập để tìm và sửa chữa. Với DRY chúng ta có thể thấy chúng chiếm 30% hiệu năng nhưng chúng ta không phải sửa chúng 10 lần.

Không phải tôi đã nói sao, chúng ta không có thời gian dành cho việc tìm và sửa từng cái một.

Có một trường hợp mà chúng ta thường làm trái quy tắc DRY đó là nhu cầu về các dãy dữ liệu. Một kỹ thuật thường dùng để cài đặt các query chính duyệt qua bộ lưu trữ ấy và sau đó thực hiện query với từng phần tử:

public class UsageExample {
    private ArrayList<Customer> allCustomers = new ArrayList<Customer>();
    // …
    public ArrayList<Customer> findCustomersThatSpendAtLeast(Money amount) {
        ArrayList<Customer> customersOfInterest = new ArrayList<Customer>(); 
        for (Customer customer: allCustomers) { 
                if (customer.spendsAtLeast(amount)) 
                    customersOfInterest.add(customer);
        }
        return customersOfInterest;
    }
}

Bằng việc cho client thấy dãy dữ liệu thô này, chúng ta đã làm trái quy tắc. Điều này không chỉ giới hạn khả năng sửa chữa, nó còn ép buộc người dùng code của bạn vi phạm DRY bởi từng thứ trong đó tiềm ẩn khả năng có thể bị thay đổi trong cùng query. Tình huống này có thể được tránh bằng cách loại bỏ việc thể hiện bộ lưu trữ trên khỏi API.

Trong ví dụ này chúng tôi sẽ giới thiệu cho bạn một kiểu dữ liệu miền chuyên biệt mới gọi là CustomerList. Class mới này đóng vai trò vô cùng ý nghĩa trong miền chương trình. Nó sẽ đóng vai trò là ngôi nhà chung của tất cả các query.

Kiểu dữ liệu mới này cho phép chúng ta theo dõi liệu những query tiêu thụ hiệu năng như thế nào. Bằng việc hợp nhất những query này lại với nhau vào chung một class từ đó giúp dễ dàng đánh giá nhu cầu lựa chọn thứ cần được thể hiện, như là một

ArrayList, đến cho client. Điều này cho phép chúng ta sự tự do trong việc thay đổi cách thiết lập này mà không phải lo lắng về việc ảnh hưởng đến mối liên lạc của người dùng.

public class CustomerList {
    private ArrayList<Customer> customers = new ArrayList<Customer>(); 
    private SortedList<Customer> customersSortedBySpendingLevel = new SortedList<Customer>();
    // …
    public CustomerList findCustomersThatSpendAtLeast(Money amount) {
        return new CustomerList(
                    customersSortedBySpendingLevel.elementsLargerThan(amount)
                );
    }
}

public class UsageExample { 
    public static void main(String[] args) {
        CustomerList customers = new CustomerList();
        // …
        CustomerList customersOfInterest = customers.findCustomersThatSpendAtLeast(someMinimalAmount);
        // …
    }
}

Trong ví dụ này, bằng việc bám chặt DRY đã cho phép chúng ta giới thiệu một chương trình lập chỉ mục thay thế với danh sách đã được sắp xếp gắn với giá trị phụ thuộc vào mức độ chi của khách hàng. Quan trọng hơn những chi tiết của chương trình trên, làm theo nguyên tắc DRY giúp chúng ta tìm và sửa chữa sự nghẽn cổ chai dễ dàng hơn so với việc thực hiện điều đó với code được viết theo nguyên tắc WET.