CQRS之旅——旅程2(分解領域)
旅程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”網站或通過[email protected]讓我們知道。
折扣限界上下文: 處理會議座位的購買管理和應用折扣。該會議與主系統三個已存在的限界上下文整合在一起。
偶爾斷開連線的會議管理客戶端:這個限界上下文用於處理會議現場的管理,具有處理標籤列印、記錄參會者到達情況和額外座位銷售的功能。
提交和進度管理限界上下文:用於處理使用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希望儘快釋出一個可用的應用程式,但是還要能夠在開發過程中新增計劃的特性和客戶要求的特性,並且不需要停機就能進行升級。