Jan. 26 22:10~22:59
▲ezKanban使用者註冊範例
學員的問題
今天Teddy和ezKanban團隊mobbing的時候,有一位去年上【領域驅動設計與簡潔架構入門實作班】的學員突然傳訊息給Teddy。一開始對方說要詢問anti-corruption layer實作的問題,但依據Teddy多年的經驗,當有人覺得他的問題是A的時候,通常他的問題都不是A,而是X或Y或Z。
討論到後來對方給了Teddy一張從網路抓下來的圖如下:
▲圖1:學員用來詢問Teddy的例子,擷取自網路
對方將付款服務定義一個介面,放在application service layer(也就是clean architecture的use case layer)。他的問題是:
- 當付款成功之後,是否由application service 發出Paid Successfully領域事件?
- 如果是,但DDD不是提到領域事件是由Aggregate Root所發出,從application service發出領域事件OK嗎?
***
區分不同的視角
Teddy記得Martin Fowler在《UML Distilled》提到,一個class diagram有三個不同的視角(perspective):
- Analysis
- Design
- Implementation
如果讀者把analysis class diagram當成implementation class diagram來解讀,一定會覺得圖中少了很多細節,甚至會誤解這張圖。
同樣道理,這位學員從網路上看到的event storming例子,頂多就是process level的圖,還沒到design level,所以直接用這張圖來推論實作,就可能會造成誤解。Teddy從design level的視角,將圖1重新繪製如圖2。
▲圖2:將圖1加上Aggregate,進入design level event storming
圖2有兩個Aggregate,因為還不知道要叫什麼名子,先用AA和BB代表。圖2的主流程如下:
- 使用者執行付款(Pay,藍色便利貼)命令
- 該命令送給AA(黃色便利貼)
- AA與外部系統(粉紅色便利貼,此範例的外部付款系統為PayPal)溝通付款細節
- 如果付款成功則產生Paid Successfully領域事件(橘色便利貼)
- 該領域事件引發一條規則(紫色便利貼)—寄送付款成功的信件給使用者
- 因而又觸發了寄送Email(Send Email)命令
- 以此類推
根據以上分析,很顯然付款服務應該是一個domain service而非application service。AAA呼叫付款服務這個domain service,並依據付款的成功與否送出不同的領域事件。如此一來便回答了學員的問題。
***
友藏內心獨白:視角清楚,思慮也跟著清楚,答案就在不遠處。
在 Stackoverflow 看過一則答案,Application Service 決定要做什麼(What to do),Domain Service 決定怎麼做(How to do)。來源:https://stackoverflow.com/a/65461735/5203951
回覆刪除所以當 Domain Service 執行結束,回傳的資料可以帶有 Domain Events(例如 Event[]),然後再由 Application Service 決定該怎麼處理這些事件(例如:可以直接透過 Publisher 發布這些事件)。
這樣既保留了 Domain 來發出領域事件,又可以確切掌控、避免 Domain 重複發出事件。因為有太多人在 Domain 裡發布事件,結果事情可能還沒 Save 到持久化資料庫,就被其他服務當作已經處理完成。