觀《if (domain logic) then CQRS, or Saga?》所悟

引言

Udi Dahan曾在2017年阿姆斯特丹的DDD歐洲年會上發表過一篇演講——if (domain logic) then CQRS, or Saga。視頻是UP主從Youtube搬運的,我聽力水平通常,因此如下內容有所偏頗的話,還請見諒。git

在演講中,他提到了Sandbox、Private Domain、Public Domain和Collaboration Domain等一些概念,爲更好地應用DDD開闢了不一樣視角。如下即是個人思考與收穫。github

正文

Udi用級聯刪除的例子,引出了沙盒Sandbox。錯誤的級聯刪除操做,特別是在數據庫中Table級別上的刪除操做,對任何一個系統而言均可謂滅頂之災。因此瓜熟蒂落的,咱們會使用給數據行打上某種刪除標誌的方法,稱之爲「軟刪除」,避免數據被完全刪除。這就象操做系統裏的回收站同樣,給了咱們一次反悔的機會。若是在全部的軟件系統裏都有這樣一個安全沙盒,是否是就徹底解決了刪除問題?數據庫

  • 對此,我認爲,對於系統中的全部刪除操做,首先都應該有領域行爲上的具體含義,好比解僱員工、取消訂單、停產產品等等。其次,還要考慮受到刪除操做影響的數據,要限定在哪一個範圍,它們是否有留存下來的業務價值。好比解僱員工後,與之相關的薪酬記錄就不能刪除,不然會致使帳面錯誤。反之,只在薪酬記錄裏有個員工ID,卻查不到這名員工的姓名、職務等具體信息,也會發生錯誤。再或者,這名員工先被裁人,以後在招聘時被優先聘用時,如何處理其原有信息,等等。因此,「刪除」操做不能簡單論之,必須是從業務領域的角度去思考和命名——其到底是何種業務操做,這種操做在業務上應致使何種後果。好比僱員被解僱後,其全部數據被凍結,其僱員信息再也不會更新,其薪酬不會再發放。

隨後,Udi用博客做爲例子,引出了Private DomainPublic Domain的概念,並闡述了Sandbox與兩者之間的聯繫。一篇隨筆被正式發佈前,博主能夠在編輯頁面隨便折騰。而在隨筆正式發佈後,全部的修改和刪除操做就須要慎重了。此處,發佈前的隨筆處於Private Domain,發佈後則進入了Public Domain。對處於Private Domain範圍內的私有數據,咱們能夠隨意地增刪查改,而不用顧忌任何的業務規則和約束。而當私有數據被推送到Public Domain時,則必須順利經過各類規則的審覈與驗證,進而成爲構成系統的固定組成部分。其中,每一個Private Domian對應一個Sandbox,用戶能夠隨心所欲,而沒必要擔憂對系統形成實質影響。安全

  • 對此,我認爲,每一個Sandbox都對應某個具備領域含義的實體,並能夠用與之相關的領域事件做爲Private Domain與Public Domain的劃分界線。好比一份菜譜,你能夠隨意修改菜譜裏各類菜品的價格、名稱,甚至新增或者撤掉某個菜品。而在正式提交更新前,全部人仍舊會使用舊的訂價和菜名。這裏的菜譜,就是全部菜品所在的Sandbox邊界。而最終MenuUpdated事件的觸發,才標誌着操做對系統產生了實質性改變,數據已經進入Public Domain。若是沒有這個提交的步驟,讓全部的增刪查改都當即產生效果,那顧客必定會開罵了。另外一方面,若是沒有暫存修改結果的這個Sandbox,也意味着徹底不給飯店老闆活路——要改就一口氣改完,還不能自相矛盾。回到前述的刪除操做也是同理。當數據還在Private Domain時,咱們能夠放心地刪除之。而當數據已經進入Public Domain後,就必須去發掘刪除操做背後的領域含義了,並由此衍生出更復雜的領域邏輯和領域行爲。

Udi接着商品被刪除的例子,延伸到購物車中已加入的商品售罄或被停售的狀況,提出Collaboration Domain的概念。在競態條件(即併發條件下的競爭條件)下,即代表有多個參與者須要對同一個數據進行操做,此時屬處的領域即Collaboration Domain。這樣的協做領域,一般能夠圍繞if語句進行發掘。有if判斷涉及其餘的實體,則一般代表該數據也可能會被其餘參與者改變。此時,CQRS成爲很天然的選擇。由於命令執行的環境是通過事先檢驗的,因此命令老是能成功執行。在這樣的設定下,把一個用戶下單的操做分割爲多個步驟,在放入購物車和提交訂單時分別進行一次商品有效性的檢驗。併發

  • 對此,我認爲,引入CQRS是由於將命令與查詢分離後,檢驗執行環境的部分將由一組查詢構成,改變系統狀態的部分則由一組命令組成,這樣將更容易發現競態條件,從而作出合理的選擇。

爲了減小檢驗的次數,Udi借Shopping Cart Timeout的例子引出了Collaboration Timeout的概念。給購物車一個活動狀態的超時設定:用戶放入商品時,購物車進入激活狀態,跨入協做領域,此時因商品在售,訂單能夠成功提交;用戶未在超時前提交訂單的,購物車進入失活狀態,退出協做領域,以後商品將因售罄或停售而沒法再加入購物車。框架

  • 對此,我認爲,此時的購物車更象是一個願望清單(Udi在演講裏也有說起),這樣的Timeout與超賣都是解決最終一致性條件下的不一樣解決方案。MSDN CQRS Journey第164頁提到的方案,是根據代價大小,選擇對客戶作出賠償或者在付款前加鎖斷定,讓其餘人等待一小段時間。當席位較多時,由於競爭風險小,能夠將席位是否夠用的查詢交付異步執行,使用戶等待時間減小;當席位緊張時,容許提交失敗的用戶修改訂單。惟品會採用的方式,是在商品加入購物車後,將該商品暫時鎖定,保證用戶在超時前能成功下單。

因爲Collaboration Domain和CQRS的存在,Udi指出,必須改變傳統的思考方式,由於Saga將更廣泛地出如今模型之中。對此不能有退縮和猶豫,應當與領域專家深刻交流,使本身也成爲業務專家,確保每一個流程都徹底可控。最後,Udi提出消息中間件是實現Saga的重要工具,因而順手推介了一下本身維護的NServiceBus框架。dom

  • 對此,我認爲,以用戶購物這個Saga爲例,將由用戶註冊->查看商品詳情->放入購物車->提交訂單->完成支付等多個流程協做完成,而不是簡單地放在一個或幾個數據庫事務裏完成。在不一樣聚合之間以消息或事件爲紐帶,是處理Saga的核心與關鍵。因此CQRS、Event Sourcing以及Message Queue都將是實現DDD的利器。
相關文章
相關標籤/搜索