# 84: Suy nghĩ trong từng States

Mọi người thường có một mối quan hệ kì lạ với các states(1). Sáng nay tôi đã thưởng chút cafe tại một cửa hàng gần nhà để chuẩn bị cho công việc. Thức uống yêu thích ❤️️ nhất của tôi là latte, nhưng nhân viên bán hàng lại không cho vào ly bất kì giọt sữa nào, và họ đã nói với tôi thế này:

Xin lỗi quý khách, chúng tôi không còn một tí tì ti sữa nào

Đối với một lập trình viên, đó là một câu nói kì quặc. Cho dù bạn có hết sữa hay là không, chẳng có gì có thể khẳng định cho điều đó. Có thể cô ấy đang cố nói với tôi rằng quán của họ đã hết sữa cả tuần nay, nhưng kết quả chẳng có gì thay đổi — ngày hôm nay tôi vẫn phải uống một ly espresso.

Trong các tình huống ngoài đời thực, thái độ ung dung của mọi người đối với state không phải là một vấn đề lớn. Tuy nhiên nhiều lập trình viên vẫn còn đang khá mơ hồ về state, và đó mới là vấn đề đáng nói.

Hãy xem như một webshop đơn giản chỉ xài thẻ tín dụng và không lập hóa đơn cho khách hàng, sử dụng một class Oder chứa phương thức này:

public boolean isComplete() { 
    return isPaid() && hasShipped();
}

Rất hợp lí đúng không? Kể cả nếu biểu thức được trích xuất độc đáo thành một phương thức thay vì sao chép ở mọi nơi, thì biểu thức này vẫn không nên được tồn tại và sự thật là nó đã nêu bật được một vấn đề. Tại sao ư? Bởi vì một đơn đặt hàng không thể được vận chuyển trước khi nó được thanh toán. Do đó, hasShipped không thể cho là đúng trừ khi isPaid đúng, là một phần làm nên một biểu thức rườm rà. Bạn có thể vẫn muốn isComplete để code được rõ ràng hơn, nhưng điều đó sẽ làm cho nó trở thành như thế này:

public boolean isComplete() {
    return hasShipped();
}

Trong công việc của mình, tôi luôn thấy được cả những lần kiểm tra thiếu và những lần kiểm tra dư. Đây chỉ là một ví dụ nhỏ, nhưng khi bạn tăng cường “hủy bỏ” và “trả lại”, nó sẽ trở nên ngày càng phức tạp, đồng thời những nhu cầu cho việc xử lý state tốt cũng ngày một gia tăng. Trong trường hợp này, một order chỉ có thể là một trong ba states riêng biệt:

  • Trong quá trình: Có thể thêm vào hoặc loại bỏ items. Không thể vận chuyển.
  • Thanh toán: Không thể thêm hoặc loại bỏ items. Có thể được vận chuyển.
  • Vận chuyển: Hoàn thành. Không có thêm bất kì thay đổi nào được chấp nhận

Những states đó rất quan trọng và bạn cần kiểm tra xem bản thân có đang ở trong state mình mong đợi trước khi thực hiện các thao tác hay không, nếu không thì hãy di chuyển đến một state khác phù hợp hơn. Nói ngắn gọn thì bạn phải bảo vệ các đối tượng của mình một cách cẩn thận và tại một địa điểm thực sự hợp lí.

Nhưng bằng cách nào để bắt đầu thực hiện “suy nghĩ trong các states”? Trích xuất các biểu thức cho những phương thức có ý nghĩa là một sự khởi đầu không tồi, nhưng đó vẫn chỉ là bước thứ nhất. Nền tảng của việc này chính là để am hiểu về các state machines(2). Tôi biết là các bạn có những kí ức không tốt về CS class(3), nhưng tạm thời hãy quên chúng đi, các state machines không hề làm khó bạn chút nào. Hãy hình dung để làm cho chúng trở nên đơn giản và dễ trao đổi hơn. Hãy chạy thử code để chỉ ra các states hợp lệ và không hợp lệ, sau đó chuyển tiếp và giữ nguyên sự chính xác của chúng. Khi nghiên cứu về các State pattern(4), nếu thực sự thoải mái, hãy xem thử công nghệ Design by Contract, việc đó sẽ giúp bạn biết được rằng một state là hợp lệ bằng cách xác nhận dữ liệu đầu vào và đầu ra của mỗi phương thức được công khai.

Nếu state của các bạn không chính xác, chắc hẳn đó là một bug, và nếu bạn không ngưng nó lại, nguy cơ bị mất dữ liệu là rất cao. Một điều nữa, khi nhận thấy các state checks bị nhiễu, hãy học cách sử dụng một công cụ, tạo code, weaving(5), các khía cạnh để giải quyết vấn đề đó. Bất kể các bạn chọn cách tiếp cận nào, “suy nghĩ ở trong mỗi state” sẽ làm cho các đoạn code được đơn giản và mạnh mẽ hơn.

💬 Chú thích:

  1. State: State là một đối tượng Javascript lưu trữ dữ liệu động của một component. State là dữ liệu động, nó cho phép một component theo dõi thông tin thay đổi ở giữa các kết xuất (render) và làm cho nó có thể tương tác. State chỉ có thể được sử dung ở trong một component sinh ra nó.
  2. State machines: State machine là một mô hình quản lý quá trình chuyển trạng thái. Nó được ứng dụng rộng rãi trong nhiều ứng dụng. Một trong đó là về cài đặt các workflow.
  3. CS class: C# class.
  4. State pattern: State Pattern là một trong những mẫu thiết kế thuộc nhóm behavioral cho phép một object có thể biến đổi hành vi của nó khi có những sự thay đổi trạng thái nội bộ. Mẫu thiết kế này có thể được hiểu gần giống như Strategy, nó có thể chuyển đổi các chiến lược thông qua các phương thức được định nghĩa trong interface.
  5. Weaving: Quá trình kết nối các thành phần Aspect và Non-aspect(chẳng hạn như Object, Types) của một chương trình để tạo nên Advised Object gọi là Weaving.