September 10 14:20~15:20
▲跳出盒子思考,有時候跨層存取也是OK滴
緣起
前幾天Teddy在讀《Domain Modeling Made Functional: Tackle Software Complexity with Domain-Driven Design and F#》,看到第3章有一個段落談Code Structure Within a Bounded Context。這是一個很有趣的議題但談得人並不多,既使是這本書也沒有講得很詳細,但其中有一張如圖1所示的圖引起我的注意。
▲圖1:每一個end-to-end功能橫切軟體架構的每一層,圖片節錄自《Domain Modeling Made Functional: Tackle Software Complexity with Domain-Driven Design and F#》,53頁。
***
Clean Architecture
看到圖1讓Teddy想起《Clean Architecture》第34章談到四種區分package的方法,回頭把這一章又讀了一次,看到圖2這段文字:
▲圖2:《Clean Architecture》 311頁。
當年Teddy在讀這段文字的時候並沒參透這個問題:「為什麼在CQRS架構中就特意允許跨層參考?」雖然Teddy知道CQRS架構模式但自己沒有實際實作過,但這次讀懂了。
前陣子讀了一本奇書:《CQRS》。如圖3所示,書中明白建議:
- 領域驅動設計(Domain-Driven Design;DDD)只需要應用在那些會改變系統狀態的Command。換句話說,只需要在Command套用DDD與Clean Architecture。
- 針對不會改變系統狀態的Query不需要套用DDD,甚至根本也不要設計領域物件,直接讀取資料庫然後產生前端需要的View Model即可,這樣速度更快。
▲圖3:節錄自《CQRS》
看完這本書之後Teddy就把ezKanban的use case改成Command與Query。昨天進一步和ezKanban團隊把帳號管理專案的package改用package by feature的方式來管理,如圖4所示。
▲圖4:ezKanban的帳戶管理專案採用package by feature
在重構成package by feature的過程中,GetUserUseCase這個Query與其它會改變系統狀態的use case分別放到不同的package。此時GetUserUseCase已經完全沒有對於User這個領域物件的依賴,如圖5所示它直接透過新的UserQueryRepository查詢資料庫並回傳UserDto給前端。換句話說,CQRS的Query端,故意省略domain model與資料庫之間的轉換,跳過domain model直接讀取資料庫。也就回答了圖2的問題。
▲圖5:直接操作資料庫並回傳DTO給前端
***
友藏內心獨白:繞了一大圈啊。