Clean Architecture và CQRS xuất hiện trong gần như mọi bài viết về .NET hiện nay, nhưng ít bài nói rõ khi nào chúng đáng dùng và khi nào chỉ làm dự án nặng thêm. Bài viết này nhìn cả hai dưới góc độ chi phí — cái được và cái phải trả.
Clean Architecture giải quyết điều gì
Ý tưởng cốt lõi rất ngắn: quy tắc nghiệp vụ không được phụ thuộc vào cơ sở dữ liệu, framework hay giao diện. Chiều phụ thuộc chỉ đi từ ngoài vào trong.
Trong một giải pháp .NET, cách chia thường gặp là bốn tầng:
- Domain — thực thể, hằng số, kiểu giá trị. Không tham chiếu tới gì bên ngoài.
- Application — luồng nghiệp vụ, lệnh và truy vấn, giao diện trừu tượng cho những thứ bên ngoài.
- Infrastructure — truy cập dữ liệu, gửi thư, lưu tệp, gọi dịch vụ ngoài.
- WebApi — điểm vào, xác thực, định tuyến, đăng ký phụ thuộc.
Lợi ích thật nằm ở chỗ: khi cần đổi cách lưu trữ hay đổi thư viện gửi thư, phần chứa quy tắc nghiệp vụ không bị đụng tới. Và quan trọng không kém, quy tắc nghiệp vụ kiểm thử được mà không cần dựng cơ sở dữ liệu.
Cái phải trả
Không có bữa trưa miễn phí. Ba khoản chi phí rõ rệt:
- Nhiều tệp hơn cho cùng một việc. Một chức năng đơn giản vẫn cần lệnh, bộ xử lý, bộ kiểm tra dữ liệu, ánh xạ. Với ứng dụng chỉ đọc ghi dữ liệu thuần tuý, đây là chi phí thuần.
- Đường đi khó lần hơn với người mới. Bù lại bằng quy ước đặt tên và thư mục nhất quán — quy ước tốt quan trọng hơn sơ đồ kiến trúc đẹp.
- Dễ bị làm nửa vời. Một lần gọi thẳng cơ sở dữ liệu từ tầng ứng dụng là đủ để phá vỡ lợi ích của cả cấu trúc, mà không ai nhận ra ngay.
CQRS: tách đường đọc và đường ghi
CQRS thường bị nhầm với việc phải có hai cơ sở dữ liệu. Ở mức thực dụng nhất, CQRS chỉ là: lệnh thay đổi dữ liệu đi một đường, truy vấn đọc dữ liệu đi một đường khác, và hai đường đó không dùng chung mô hình.
Lý do đáng làm:
- Đường ghi cần kiểm tra quy tắc, ghi nhật ký, giữ giao dịch nguyên vẹn.
- Đường đọc cần trả đúng dữ liệu màn hình cần, càng ít vòng truy vấn càng tốt, và thường không cần theo dõi thay đổi của thực thể.
Khi hai đường dùng chung một mô hình, đường đọc bị kéo theo những trường không cần, còn đường ghi bị ép mở rộng cho vừa nhu cầu hiển thị. Tách ra giúp cả hai đơn giản hơn.
Đường ống xử lý — nơi CQRS trả lãi rõ nhất
Khi mọi thao tác đều đi qua một điểm trung gian, những việc lặp lại được xử lý một lần cho toàn hệ thống:
- Kiểm tra dữ liệu đầu vào tự động trước khi bộ xử lý chạy, không cần viết lại ở từng chỗ.
- Ghi nhật ký và đo thời gian cho mọi thao tác, giúp phát hiện điểm chậm mà không cần thêm mã rải rác.
- Xử lý lỗi thống nhất, để mọi lỗi nghiệp vụ trả về cùng một khuôn dạng cho phía giao diện.
- Giao dịch đóng mở ở một nơi duy nhất, thay vì phụ thuộc vào việc lập trình viên nhớ gọi đúng.
Khi nào không nên dùng
Một ứng dụng nhỏ có vòng đời ngắn, vài màn hình quản lý danh mục, đội một hoặc hai người: kiến trúc phân tầng nhẹ là đủ, và sẽ hoàn thành nhanh hơn.
Ngưỡng đáng cân nhắc chuyển sang cấu trúc đầy đủ:
- Hệ thống dự kiến sống nhiều năm và đổi người bảo trì.
- Có quy tắc nghiệp vụ thật sự, không chỉ là biểu mẫu nhập liệu.
- Nhiều điểm vào cùng dùng chung nghiệp vụ: giao diện web, ứng dụng di động, công việc nền, tích hợp bên ngoài.
Vài lỗi thường gặp khi áp dụng
- Thực thể phình thành nơi chứa mọi thứ. Nếu mô hình miền mang cả thuộc tính chỉ để hiển thị, ranh giới đã bắt đầu nhoè.
- Bộ xử lý gọi bộ xử lý khác. Nên tách phần dùng chung thành dịch vụ riêng, để luồng vẫn đọc được từ trên xuống.
- Quá nhiều lớp trừu tượng. Mỗi giao diện chỉ có đúng một cài đặt và không phục vụ kiểm thử thì nên xem lại.
- Kiểm thử chỉ ở mức đơn vị. Phần dễ sai nhất thường là truy vấn dữ liệu, mà truy vấn chỉ lộ vấn đề khi chạy thật.
Kết luận
Clean Architecture và CQRS không phải tiêu chuẩn đạo đức, chúng là công cụ đánh đổi: bỏ ra sự dài dòng ban đầu để đổi lấy khả năng thay đổi về sau. Với hệ thống quản trị doanh nghiệp — nơi quy tắc nghiệp vụ nhiều, thay đổi liên tục và tuổi thọ tính bằng nhiều năm — đánh đổi này thường có lợi. Với một công cụ nội bộ dùng vài tháng thì không.




