領域驅動設計系列 (六):CQRS


CQRS是Command Query Responsibility Seperation(命令查詢職責分離)的縮寫。 世上很多事情都比較復雜,但是我們只要進行一些簡單的分類后,那么事情就簡單了很多,比如我們把人分為男人和女人,也可以把人分為大人和小孩,還比如,我們說國內和國外,城市和農村。經過一些類似這樣的划分,我們的對不同的類就有不同的關注。 這樣我們就會有婦女兒童醫院專門讓女人生孩子,而不會建一個醫院讓男女都生孩子。

CRUD

CRUD (Create, Read, Update, Delete) 增查改刪,我們很多系統都是對數據的增查改刪。過去我們很多系統比較簡單,基本上增加的數據就是你要查詢的數據,所以很多時候其實一個簡單的Excel就能搞定。 而且增刪改查也足夠的簡單,所以我們很多系統分層后在數據層Repository里仍是對單表的增刪改查,這樣對不少的系統都符合。

但是,系統規模稍微大一點,我們都知道我們的數據庫里的數據模型很難和我們業務層需要的模型一致。 於是我們引入了Domain Model, Repository里就會做Domain Model的來回轉換

1

同時我們在UI層要的數據,往往又和具體的Domain不同,這個時候我們又要定義一個ViewModel. 而這些ViewModel又是組合不同的DomainModel得來。

傳統的代碼里的問題:

  • 領域里有很多分頁和排序,尤其是Repository里
  • 查詢的方法里暴露了很多不應該有的領域模型的屬性,因為需要組裝DTO
  • 如果使用ORM,預加載了很多數據以提高性能,但是占用大量內存,而且需要維護這些數據。
  • 加載組合龐大的數據,比如頁面是需要一個名字,我們也會把整個User數據取出來。

重要的原來把數據混在一起,復雜的查詢相當難以優化。 尤其是數據庫出現大量的Join 系統性能極速下降。

最重要的是我們把讀寫都放在了一起,顯得責任不夠清晰,代碼也更復雜了一些,比如讀數據是不太關心事物的,讀數據是不需要驗證的,只有寫的時候才需要做數據校驗,這也比較符合SRP(單一職責),但是用CRUD的思維是我們全都混在了一起。

CQRS

我們仔細看CRUD, 其實可以更簡單的分為讀(R)和寫(CUD), 我們想想大部分情況都是,一個方法要么是執行一個Command完成一個動作,要么就是查詢返回數據。 比如我們回答問題的人不應該去修改問題。

當我們讀寫分離后,我們對應的代碼也會分離。

數據存儲

寫的一端需要保證事物,所以一般數據存儲為第三范式,
讀的一端一般都是反范式可以避免Join操作,這樣我們只需要把數據存儲為第一范式

擴展

大部分的系統里寫數據要遠遠少於讀數據,並且一般都是每次修改很少的一部分數據,所以在寫這端擴展都不是特別緊迫,讀數據基本都遠大於寫數據的次數, 所以擴展就更重要。 我們很難建立同一個Model 既能給寫數據和讀數據公用而且能夠保證性能都比較好的。

查詢端

查詢端由於只是讀數據,那么所有的方法應該都是返回數據,而且返回的數據就是界面直接需要的DTO, 這樣可以減少傳統的方法中把DomainModel映射為ViewModel或者DTO. 同時可以減少傳統的領域里的一些混亂。

寫端

由於把讀分離出去,所以我們就只關注寫,那么我們寫這一段需要保證事物,數據輸入的驗證,另外一般寫這一端都不需要及時的看到結果,所以大部分都需要一個void方法就可以,那么讓我們系統異步就更加方便。這樣使系統的擴展性大大增強。

代碼更容易集中處理

當我在一些系統中使用CQRS后,很多地方代碼大大簡化,比如我所有的寫操作都是一個Command, 那么我定義一個UICommand, 讓所有的Command集成這個,那么我可以在這個UICommand里做一些通用的處理,比如Validation

同時我只需要定義一個CommandBus, 然后把對應的CommandBus分發到對應的Handler里(我前面幾篇有實例代碼),那么代碼的耦合度大大降低。

代碼分工協作更容易

由於讀這一端直接讀數據,而且對數據庫沒有任何操作,那么我們可以根據UI定義對應的DTO, 那么開發的時候我們可以用Mock數據,至於數據怎么存的,那么我們隨后只要添加一層Thin Data Layer即可,實際上當我們使用CQRS后,很多時候我們把數據保存的時候都直接保存為Denormalize的,那么從數據里直接查詢單表的數據就可以拿到頁面需要的數據,大大提升讀取數據的性能,同時代碼也會極其的簡化,開發讀這一段代碼的開發人員甚至都不需要對業務有太多了解。

實現

簡單的實現

2 3

使用的Event后

4

使用了Event Source 和Service bus后

5


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM