旅程2:分解領域
設計停靠站點
“沒有石頭就沒有拱門” --馬可波羅
在本章中,我們將對Contoso會議管理系統進行一個高層次的概述。這將幫助您理解應用程序的結構、集成點以及應用程序的各個部分之間的關系。
在這里,我們借用Eric Evans在他的書《領域驅動設計 軟件核心復雜性應對之道(Addison-Wesley Professional, 2003)中描述的領域驅動設計(DDD)方法來描述這個高級結構。DDD是成功實現CQRS模式的先決條件雖然還沒有達成普遍的共識,但我們團隊依然決定按照CQRS社區的慣例使用DDD里眾多概念和方法,例如領域、限界上下文,和聚合。參考指南的第1章“上下文中的CQRS”更詳細地討論了DDD和CQRS模式之間的關系。
本章使用的定義
在本章中,我們使用了一些術語,我們將在后面定義它們。有關更多細節和可能的替代定義,請參見參考指南中的第1章“上下文中的CQRS”。
-
領域(Domain):領域是指Contoso會議管理系統的業務域(參考實現)。第一章“我們的領域:Contoso會議管理系統”概述了這個領域。
-
限界上下文(Bounded Context):術語限界上下文來自Eric Evans的書。簡而言之,Evans引入這個概念是為了將一個大型的、復雜的系統分解成更易於管理的部分。大型系統由多個限界上下文組成。每個限界上下文都是自己包含領域模型的上下文,並且有它自己的通用語言(Ubiquitous Language)。您還可以將限界上下文看做明確定義了一致性邊界的自主業務組件。一個限界上下文通常通過引發事件(Raising Events)與另一個限界上下文通信。
Gary(CQRS專家)發言:
當你使用CQRS模式時,經常使用事件在限界上下文中進行通信。集成還有其他方法,比如在數據庫級共享數據。 -
上下文映射:根據Eric Evans的說法,您應該“描述模型之間的聯系點,明確所有通信需要的轉換,並突出任何共享的內容。”這個練習產生了所謂的上下文映射,它有幾個用途,包括提供整個系統的概覽,以及幫助人們理解不同的限界上下文如何相互交互的細節。
會議系統中的限界上下文
-
訂單和注冊限界上下文:在訂單和注冊限界上下文中包含預訂、付款和注冊項。當注冊用戶與系統交互時,系統創建一個訂單來管理預訂、付款和注冊。訂單包含一個或多個訂單項。
預訂是在會議上臨時預訂一個或多個座位。當注冊用戶開始訂購會議上的一些座位時,系統會為這些座位創建預訂。然后,其他用戶無法預訂這些座位。預訂保留15分鍾,在此期間,登錄人可以通過支付座位的費用完成訂購過程。如果用戶沒有在15分鍾內付款,系統將刪除該預訂,其他用戶可以繼續預訂這些座位。Carlos(領域專家)發言:
我們討論過將系統保留預訂的時間期限設置成一個參數,這樣客戶可以為每次會議調整這個預留時間。如果我們確定需要這種級別的控制,那么這可能是我們需要添加的一個特性。 -
會議管理限界上下文:在這個限界上下文中,業務客戶可以創建新的會議並管理它們。在業務客戶創建新會議之后,他可以使用電子郵件和訪問代碼來訪問查看會議的詳細信息。當業務客戶創建會議時,系統生成訪問代碼。
業務客戶可以指定以下關於會議的信息:- 名稱、描述和slug(用於訪問會議的URL的一部分)。
- 會議的開始和結束日期。
- 會議提供的不同座位類型和配額。
此外,業務客戶可以通過發布或取消發布來控制會議在公共網站上的可見性。
業務客戶還可以使用會議管理網站查看訂單和參會者列表。
-
支付限界上下文:支付限界上下文負責管理會議管理系統和外部支付系統之間的交互。它將必要的付款信息轉發給外部系統,並接收付款被接受或拒絕的結果。它將支付的成功或失敗報告給會議管理系統。一開始,支付限界上下文將假定業務客戶在第三方支付系統中有一個帳戶(盡管不一定是商家帳戶),或者業務客戶將接受發票支付。
旅程中未包含的幾個限界上下文
雖然這幾個限界上下文沒有進入Contoso會議管理系統的最終版本,但是做了一些工作。社區成員正在開發這些以及一些其他功能,任何帶外發布和更新都將在“CQRS之旅”網站上公布。如果您想對這些限界上下文或系統的任何其他方面有所貢獻,請訪問項目“CQRS Journey”網站或通過cqrsjourney@microsoft.com讓我們知道。
-
折扣限界上下文: 處理會議座位的購買管理和應用折扣。該會議與主系統三個已存在的限界上下文集成在一起。
-
偶爾斷開連接的會議管理客戶端:這個限界上下文用於處理會議現場的管理,具有處理標簽打印、記錄參會者到達情況和額外座位銷售的功能。
-
提交和進度管理限界上下文:用於處理使用Node.js編寫的論文提交和會議事件調度。
在這個版本中沒有實現候選清單功能,但是社區成員正在開發這個特性和其他特性。任何帶外發布和更新都將在“CQRS之旅”網站上公布。
Contoso會議管理系統的上下文映射
圖1和后面的列表顯示上下文映射,該映射顯示構成完整系統的不同限界上下文之間的關系,因此它提供了系統如何組合在一起的高級概述。盡管這個上下文映射看起來非常簡單,但是這些限界上下文的實現,以及更重要的是它們之間的交互,都是相對復雜的。這使我們能夠遭遇並處理CQRS模式和Event Sourcing的廣泛問題,並有了一個豐富的源頭來獲取很多寶貴的經驗和教訓。
Gary(CQRS專家)發言:
關於CQRS項目的一個常見說法是:很難理解所有部分是如何組合在一起的,特別是如果系統中有很多命令和事件。通常,您可以對代碼執行一些靜態分析,以確定事件和命令是在哪里被處理的,但是很難查明它們是在哪里發起的。在高層次上,上下文映射可以幫助您理解不同限界上下文和相關事件之間的集成。維護有關命令和事件的最新文檔可以提供更詳細的信息。另外,如果你有測試,使用命令作為輸入,然后檢查事件,您可以通過測試來了解某個特定命令的預期結果(參見第4章“擴展和提高訂單和注冊限界上下文”中的測試示例)。
圖1顯示了構成Contoso會議管理系統的三個限界上下文。圖中的箭頭表示它們之間的事件數據流。
下面的列表提供了關於圖1中的箭頭的更多信息。您可以在討論單獨限界上下文的章節中找到更多的細節。
- 在創建、更新或發布會議時報告的事件。創建或更新座位類型時報告的事件。
- 創建或更新訂單時報告的事件。當與會者被分配到座位時報告的事件。
- 要求付款。
- 確認付款的成功或失敗。
Gary(CQRS專家)發言:
會議管理限界上下文引發的一些事件是粗粒度的,包含多個字段。請記住,會議管理是一個使用創建、讀取、更新和刪除(CRUD)模式的限界上下文,不會引發細粒度的領域事件。有關更多信息,請參見第5章:“准備發布V1版本”。
為什么選擇這些限界上下文?
在旅程(開發)的規划(初期)階段,很明顯,這些是領域中的自然划分,可以包含各自獨立的領域模型。其中一些划分比其他的更容易識別。例如,很明顯,會議管理限界上下文獨立於領域的其他部分。它具有與定義會議和座位類型相關的明確定義的職責,以及與應用程序其他部分的明確定義的集成點。
另一方面,我們花了一些時間才意識到訂單和注冊限界上下文與支付限界上下文是分開的。例如,直到應用程序的V2發行版,當OrderPaymentConfirmed事件成為OrderConfirmed事件時,與支付相關的所有概念才從訂單和注冊上下文中消失。
Gary(CQRS專家)發言:
隨着我們對領域模型理解的加深,我們在整個過程中不斷細化領域模型。
更實際,從旅途的角度來看,我們想要一組限界上下文,使我們能夠發布一個可工作的應用程序並包含一些核心的功能,它可以使我們去探索許多不同的實現模式:CQRS, CQRS/ES,以及與傳統的集成,例如CRUD風格的限界上下文。
Beth(業務經理)發言:
Contoso希望盡快發布一個可用的應用程序,但是還要能夠在開發過程中添加計划的特性和客戶要求的特性,並且不需要停機就能進行升級。