Không phải CQRS áp đảo?


14

Tôi vẫn còn nhớ ngày xưa tốt đẹp của kho. Nhưng kho lưu trữ được sử dụng để phát triển xấu xí theo thời gian. Sau đó, CQRS có dòng chính. Họ thật tuyệt, họ là một luồng không khí trong lành. Nhưng gần đây tôi đã tự hỏi mình nhiều lần tại sao tôi không giữ logic đúng trong phương thức Hành động của Trình điều khiển (đặc biệt là trong Web Api, nơi hành động là một loại trình xử lý truy vấn / lệnh riêng).

Trước đây tôi đã có một câu trả lời rõ ràng cho điều đó: Tôi làm điều đó để kiểm tra vì thật khó để kiểm tra Trình điều khiển với tất cả những người độc thân không thể thay đổi và cơ sở hạ tầng ASP.NET xấu xí nói chung. Nhưng thời thế đã thay đổi và các lớp cơ sở hạ tầng ASP.NET ngày nay kiểm tra đơn vị thân thiện hơn nhiều (đặc biệt là trong ASP.NET Core).

Đây là một lệnh gọi WebApi điển hình: lệnh được thêm vào và các máy khách SignalR được thông báo về nó:

public void AddClient(string clientName)
{
    using (var dataContext = new DataContext())
    {
        var client = new Client() { Name = clientName };

        dataContext.Clients.Add(client);

        dataContext.SaveChanges();

        GlobalHost.ConnectionManager.GetHubContext<ClientsHub>().ClientWasAdded(client);
    }
}

Tôi có thể dễ dàng kiểm tra đơn vị / giả nó. Hơn nữa, nhờ có OWIN tôi có thể thiết lập các máy chủ WebApi và SignalR cục bộ và thực hiện kiểm tra tích hợp (và khá nhanh bằng cách này).

Gần đây tôi cảm thấy ngày càng ít động lực để tạo ra các trình xử lý Lệnh / Truy vấn cồng kềnh và tôi có xu hướng giữ mã trong các hành động Api trên Web. Tôi tạo một ngoại lệ chỉ khi logic được lặp lại hoặc nó thực sự phức tạp và tôi muốn cô lập nó. Nhưng tôi không chắc là tôi có làm đúng ở đây không.

Cách tiếp cận hợp lý nhất để quản lý logic trong một ứng dụng ASP.NET hiện đại điển hình là gì? Khi nào thì hợp lý để chuyển mã của bạn sang trình xử lý Lệnh và Truy vấn? Có mô hình nào tốt hơn không?

Cập nhật. Tôi tìm thấy bài viết này về phương pháp DDD-lite. Vì vậy, có vẻ như cách tiếp cận của tôi về việc chuyển các phần mã phức tạp sang các trình xử lý lệnh / truy vấn có thể được gọi là CQRS-lite.


1
Tôi không thấy CQRS làm cho mọi thứ trở nên dễ kiểm tra hơn / là bất kỳ trợ giúp nào với singletons / bộ điều khiển / v.v. Chúng phần lớn không liên quan. Ngoài ra, bạn vẫn đang tạo một lệnh trong ví dụ (bộ đếm?) Của bạn, đó là số lẻ.
guillaume31

Nếu bạn giữ mã của mình bằng mã cơ sở hạ tầng (ví dụ: lấy địa chỉ IP của máy khách), thật khó để kiểm tra. Nếu bạn tách logic thành một truy vấn / lệnh, nó sẽ dễ dàng hơn nhiều. Mẫu mã hơi khó hiểu, vì vậy tôi đã cập nhật nó.
SiberianGuy

1
Truy vấn và lệnh không có logic. Họ là những DTO câm. Sau đó, bạn có trình xử lý lệnh / truy vấn của mình , nhưng chúng hoàn toàn giống với dịch vụ ứng dụng, tương tác, dịch vụ kinh doanh, bạn đặt tên cho nó ... trong ngữ cảnh không phải CQRS. Đặt logic trường hợp ứng dụng / sử dụng trong một đối tượng riêng biệt hơn Bộ điều khiển không phải là một điều cụ thể của CQRS.
guillaume31

Ngoài ra, câu hỏi về Singleton so với phụ thuộc được tiêm là hoàn toàn trực giao với CQRS. Bạn có thể có một Trình điều khiển gọi một đơn vị CommandHandler gọi một đơn vị Kho lưu trữ ...
guillaume31

1
@ guillaume31, CQRS có xu hướng cồng kềnh hơn so với các cuộc gọi dịch vụ kho lưu trữ / ứng dụng. Họ thường cần 2-3 lớp (ví dụ: truy vấn, queryhandler, queryresult), cơ sở hạ tầng, v.v.
SiberianGuy

Câu trả lời:


17

CQRS có phải là một mô hình tương đối phức tạp và tốn kém không? Đúng.

Có quá kỹ thuật không? Tuyệt đối không.

Trong bài viết gốc nơi Martin Fowler nói về CQRS, bạn có thể thấy rất nhiều cảnh báo về việc không sử dụng CQRS khi không áp dụng:

Giống như bất kỳ mô hình nào, CQRS hữu ích ở một số nơi, nhưng không phải ở những nơi khác.

CQRS là một bước nhảy vọt về mặt tinh thần đáng kể cho tất cả những người có liên quan, vì vậy không nên giải quyết trừ khi lợi ích đáng để nhảy .

Mặc dù tôi đã bắt gặp việc sử dụng CQRS thành công, cho đến nay, phần lớn các trường hợp tôi gặp phải đều không tốt ...

Mặc dù có những lợi ích này, bạn nên rất thận trọng khi sử dụng CQRS .

... Thêm CQRS vào một hệ thống như vậy có thể thêm độ phức tạp đáng kể .

Tôi nhấn mạnh ở trên.

Nếu ứng dụng của bạn đang sử dụng CQRS cho mọi thứ, thì đó không phải là CQRS được thiết kế quá mức, đó là ứng dụng của bạn. Đây là một mô hình tuyệt vời để giải quyết một số vấn đề cụ thể, đặc biệt là các ứng dụng hiệu suất cao / khối lượng lớn trong đó viết đồng thời có thể là mối quan tâm chính.

Và nó có thể không phải là toàn bộ ứng dụng, mà chỉ là một phần nhỏ của nó.

Một ví dụ trực tiếp từ công việc của tôi, chúng tôi sử dụng CQRS trong hệ thống Nhập đơn hàng, nơi chúng tôi không thể mất bất kỳ đơn hàng nào và chúng tôi có những đột biến khi hàng ngàn đơn hàng đến cùng một lúc từ các nguồn khác nhau, trong một số giờ cụ thể. CQRS đã giúp chúng tôi giữ cho hệ thống sống và đáp ứng, đồng thời cho phép chúng tôi mở rộng quy mô hệ thống phụ trợ để xử lý các đơn hàng này nhanh hơn khi cần (nhiều máy chủ phụ trợ hơn) và chậm hơn / rẻ hơn khi không cần thiết.

CQRS hoàn hảo cho vấn đề bạn có một vài diễn viên cộng tác trong cùng một bộ dữ liệu hoặc ghi vào cùng một tài nguyên.

Ngoài ra, việc truyền bá một mô hình được thực hiện để giải quyết một vấn đề duy nhất cho tất cả các vấn đề của bạn sẽ chỉ tạo ra nhiều vấn đề hơn cho bạn.


Một số liên kết hữu ích khác:

http://udidahan.com/2011/04/22/when-to-avoid-cqrs/

http://codebetter.com/gregyoung/2012/09/09/cqrs-is-not-an-arch architecture-2 /


3
Đồng ý về mọi thứ trừ phần "mô hình tương đối phức tạp và tốn kém". CQRS chỉ là tách các lần đọc từ ghi. Bạn có thể làm điều đó với băng keo, không có phần mềm trung gian / công cụ phức tạp và giữ nguyên cơ sở dữ liệu như trước đây, cho tất cả những gì nó quan tâm.
guillaume31

@ guillaume31, đó là một điểm công bằng. Tôi nghĩ rằng nó hoàn toàn phù hợp với ý tưởng từ câu hỏi ban đầu: "trong Web Api, nơi hành động là một loại lệnh / truy vấn trong chính nó". Nhưng bạn đã thấy các mẫu CQRS hoạt động (tốt nhất là github) không sử dụng các lớp riêng biệt cho các lệnh và truy vấn chưa? Đó là những gì tôi tìm thấy khi tôi cố gắng xem những người khác triển khai CQRS trong .NET như thế nào.
SiberianGuy

Vâng, nhưng nó không quá áp đảo. Đó là tiền đề cơ bản của mẫu - tách các truy vấn khỏi ghi, đọc mô hình từ mô hình miền.
guillaume31

Cách tiếp cận CQRS có thể bị giết quá nhiều trong nhiều bối cảnh, nhưng đó là một câu chuyện hoàn toàn khác. Nó không quá mức vì tất cả các chi tiết kỹ thuật nhỏ mà bạn gán sai cho CQRS trong Q của bạn, nó quá mức vì bạn không luôn cần những gì CQRS mang lại cho bạn.
guillaume31

Tôi nghĩ rằng quan điểm của Fowler chỉ có giá trị ở một điểm nhất định. SQL Views là một loại CQRS và nó có từ rất lâu đời và không ai nói chúng rất phức tạp. Vì có nhiều hương vị của CQRS, tức là các dự báo tìm nguồn cung ứng sự kiện, có thể được coi là phức tạp ở một số khu vực, trong khi có thể là tầm thường ở một khu vực khác.
Alexey Zimarev

3

CQRS không phải là sự thay thế một-một cho Kho, chính xác bởi vì đây là một mẫu phức tạp, tốn kém, chỉ hữu ích trong một số trường hợp.

Đây là những gì Udi Dahan nói về công đức:

Hầu hết mọi người sử dụng CQRS (và Tìm kiếm sự kiện cũng vậy) không nên làm như vậy.

[...]

Tôi rất tiếc phải nói rằng hầu hết các ứng dụng mẫu bạn sẽ thấy trực tuyến cho thấy CQRS đều sai về mặt kiến ​​trúc. Tôi cũng cực kỳ cảnh giác với các khung hướng dẫn bạn hướng tới một mô hình CQRS gốc tổng hợp theo kiểu thực thể.

( nguồn )

Martin Fowler:

[...] Bạn nên rất thận trọng khi sử dụng CQRS . Nhiều hệ thống thông tin phù hợp với khái niệm cơ sở thông tin được cập nhật giống như cách đọc, thêm CQRS vào hệ thống như vậy có thể tăng thêm độ phức tạp đáng kể.

( nguồn )

Cuối cùng, Greg Young:

CQRS có thể được gọi là một mô hình kiến ​​trúc.

[...]

Điều này rất quan trọng để hiểu hầu hết các mẫu kiến ​​trúc không tốt để áp dụng ở mọi nơi. Nếu bạn thấy các mẫu kiến ​​trúc trong một hướng dẫn kiến ​​trúc, bạn có thể gặp vấn đề

[...]

Thất bại lớn nhất tôi thấy từ những người sử dụng nguồn sự kiện là họ cố gắng sử dụng nó ở mọi nơi.

( nguồn )

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.