l

2021年1月26日 星期二

領域驅動設計學習筆記(17):與外部系統的互動

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的主流程如下:

  1. 使用者執行付款(Pay,藍色便利貼)命令
  2. 該命令送給AA(黃色便利貼)
  3. AA與外部系統(粉紅色便利貼,此範例的外部付款系統為PayPal)溝通付款細節
  4. 如果付款成功則產生Paid Successfully領域事件(橘色便利貼)
  5. 該領域事件引發一條規則(紫色便利貼)—寄送付款成功的信件給使用者
  6. 因而又觸發了寄送Email(Send Email)命令
  7. 以此類推

根據以上分析,很顯然付款服務應該是一個domain service而非application service。AAA呼叫付款服務這個domain service,並依據付款的成功與否送出不同的領域事件。如此一來便回答了學員的問題。

***

友藏內心獨白:視角清楚,思慮也跟著清楚,答案就在不遠處。

1 則留言:

  1. 在 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 到持久化資料庫,就被其他服務當作已經處理完成。

    回覆刪除