CQRS處理器(C#)與領域邏輯和管道 - 通過Derek Comartin的視頻解釋
命令查詢責任分離(CQRS)是一種.NET應用程式中強大的設計模式,有助於維持讀取和寫入操作之間的明確分離。 這種分離能夠提高擴展性、測試性和對複雜業務邏輯的控制。 然而,隨著您的應用程式成長,您的C# CQRS處理器可能會因邏輯而變得膨脹,難以維護和測試。
在他有見地的影片中"用領域邏輯和管道清理膨脹的CQRS處理器", Derek Comartin展示了如何通過將邏輯轉移到領域模型中並構建管道來逐步管理命令邏輯來清理這類CQRS命令處理器。本文將詳細探討Derek的做法並學習如何構建可維護性更強的C# CQRS實現。
膨脹處理器的問題
Derek首先指出許多網路應用程式中的常見情況:您打開C#的CQRS處理器,它就像一團亂。 其中有數據驗證、授權、業務邏輯、狀態轉變、事件發布、日誌記錄—所有這些都糾纏在一起。
他用一個分派貨物的命令對象來說明這一點。 處理器負責:
-
訪問數據存儲以加載貨物。
-
檢查貨物狀態是否準備好。
-
更新狀態(即更新數據)。
-
將更改保存回數據訪問層。
-
發送電子郵件。
- 發布領域事件。
所有這些都發生在一個地方。 這違反了CQRS模式的意圖,因為其目標是分離關注點並提高性能和可維護性。
將領域邏輯移到數據模型
Derek的第一步是將驗證和狀態轉變邏輯移到數據模型中。 他在Shipment類中創建了一個Dispatch()方法。 這是領域邏輯現在駐留的地方。
取代在處理器中手動檢查貨物狀態,邏輯被封裝在此方法中,確保數據完整性以及在任何地方觸發分派時一致的行為。 這是實現CQRS為依據的乾淨架構的關鍵。
例如,任何調用shipment.Dispatch()的地方都會自動執行所有驗證和狀態轉變。 這與CQRS設計模式保持一致,有助於維持處理器和領域邏輯之間的明確分離。
集中化邏輯的價值
Derek指出這種改變並不是關於增加不必要的抽象。 相反,它是關於集中使用於應用程式不同部分的邏輯。 如果多個命令處理器需要分派貨物,那麼這種自定義邏輯應存在於一個地方—領域模型內。
這使得數據模型更加健壯,而C# CQRS處理器實現更簡單且更易於維護。
引入管道模式
為了進一步清理命令處理器,Derek引入一種管道模式。 此結構將命令處理為一系列小型、單一目的的步驟,每一步都需使用一個上下文對象並調用下一步。
這在概念上類似於ASP.NET Core中間件,且每一步專注於流的特定部分:
-
檢索貨物(即讀取數據)
-
分派它(執行寫入操作)
-
發布事件
- 保存到數據存儲
這些步驟使用共享的命令對象通過管道流動。這創建了一個乾淨且模塊化的命令和查詢責任分離的實現。
管道的示例實現
在他的示例實現中,Derek用以下步驟構建了管道:
-
加載貨物—通過一個倉儲從數據訪問層拉取數據。
-
發貨—調用Dispatch()方法以應用領域邏輯。
-
添加一個領域事件—將"ShipmentDispatched"事件附加到上下文中。
-
發布事件—分發事件以通知外部系統。
- 保存更改—將更新持久化到數據存儲中。
每一步都代表命令邏輯的一個獨立部分,增強數據驗證並保持責任分開。
Derek還指出,電子郵件通知現在通過回應領域事件單獨處理。 這與事件源原則一致並促進最終一致性。
測試和維護性的好處
這種模式的最大好處之一是可測試性。 使用大型命令處理器,您可能有多個依賴項(例如,倉儲、郵件服務、日誌記錄器)。 但當您將處理器分解到管道步驟中時,每個步驟只需要幾個依賴項。
這種模塊化方法允許您使用依賴項注入輕鬆測試各個步驟,並在需要時使用虛假或模擬。 例如,如果您正在測試調用Dispatch()的步驟,您不需要模擬電子郵件服務或事件發布者。
這種關注點分離遵循責任分離CQRS模式,使您的讀取和寫入模型更清晰、更專注。
可組合性和可重用性
管道方法的另一個好處是它是可組合的。 如果您使用類似Outbox模式的東西,您可以保證事件僅在寫入模型持久化之後才發布。 這種控制水平在CQRS實現中很重要,特別是在一致性和交付保證很重要的情況下。
您還可以在不同的CQRS處理器間共享步驟—例如,一個通用的"SaveChanges"步驟或"ValidateRequest"步驟。
使用像MediatR庫這樣的工具,支持命令和查詢處理,您甚至可以在.NET Core應用程式中通過依賴注入註冊這些步驟,使用IServiceCollection服務。
要設置此系統,您可以透過Visual Studio的Package Manager Console運行Install-Package MediatR—這是C#中實現CQRS時的常見步驟。
權衡
Derek不避諱這種方法帶來的增加的複雜性。 管道引入間接性,當您查看調用堆疊時,感覺就像在迷宮中導航。
然而,對於複雜的業務邏輯,這種權衡往往是值得的。 如果一個處理器擁有10多個依賴項和數百行邏輯,CQRS使開發者能夠更好地結構和維護這些流程。
何時進行重構的最終思考
Derek最後提醒觀眾要仔細考慮他們的CQRS處理器C#實現是否真的膨脹。 並不是每一個場景都需要管道。他的目的是展示可能性,由開發者來評估他們自己的CQRS實現並確定這些模式是否會有所幫助。
他鼓勵開發者尋找他們代碼中關注點分離有助於維持一致性的地方,使代碼更模塊化,以及更好地管理讀寫操作—特別是在CQRS網路應用程式中。
結束語
Derek Comartin的影片提供了一個用領域邏輯封裝和管道清理CQRS處理器的實用指南。 這種方法有助於解決代碼膨脹問題、提升數據完整性,並通過將應用程式代碼分解為獨立的模型來增強可維護性。
無論您是在處理員工數據、產品詳細信息,或是一個新用戶命令,使用管道和領域驅動設計應用CQRS模式將使您的代碼庫更具擴展性、可測試性和健壯性。
通過使用數據傳輸對象、單獨的模型,並維持讀寫邏輯之間的明確分離,您的.NET應用程式將結構更佳並在時間推移中更容易演變。


