微服務設計為什么要選擇 DDD ?其中有一個非常重要的原因,就是采用 DDD 方法建立的領域模型,可以清晰地划分微服務的邏輯邊界和物理邊界。可以說,在 DDD 的實踐中,好的領域模型直接關乎微服務的設計水平。因此,我認為 DDD 的戰略設計是比戰術設計更為重要的。
那么我們該采用什么樣的方法,才能從錯綜復雜的業務領域中分析並構建領域模型呢?
它就是我多次提到的事件風暴。事件風暴是一項團隊活動,領域專家與項目團隊通過頭腦風暴的形式,羅列出領域中所有的領域事件,整合之后形成最終的領域事件集合,然后對每一個事件,標注出導致該事件的命令,再為每一個事件標注出命令發起方的角色。命令可以是用戶發起,也可以是第三方系統調用或者定時器觸發等,最后對事件進行分類,整理出實體、聚合、聚合根以及限界上下文。而事件風暴正是 DDD 戰略設計中經常使用的一種方法,它可以快速分析和分解復雜的業務領域,完成領域建模。
事件風暴需要准備些什么?
1. 事件風暴的參與者
事件風暴采用工作坊的方式,將項目團隊和領域專家聚集在一起,通過可視化、高互動的方式一步一步將領域模型設計出來。領域專家是事件風暴中必不可少的核心參與者。很多公司可能並沒有這個角色,那我們該尋找什么樣的人來擔當領域專家呢?
領域專家就是對業務或問題域有深刻見解的主題專家,他們非常了解業務和系統是怎么做的,同時也深刻理解為什么要這樣設計。如果你的公司里並沒有這個角色,那也沒關系,你可以從業務人員、需求分析人員、產品經理或者在這個領域有多年經驗的開發人員里,按照這個標准去選擇合適的人選。
除了領域專家,事件風暴的其他參與者可以是 DDD 專家、架構師、產品經理、項目經理、開發人員和測試人員等項目團隊成員。
領域建模是統一團隊語言的過程,因此項目團隊應盡早地參與到領域建模中,這樣才能高效建立起團隊的通用語言。到了微服務建設時,領域模型也更容易和系統架構保持一致。
2. 事件風暴要准備的材料
事件風暴參與者會將自己的想法和意見寫在即時貼上,並將貼紙貼在牆上的合適位置,我們戲稱這個過程是“刷牆”。所以即時貼和筆是必備材料,另外,你還可以准備一些膠帶或者磁扣,以便貼紙隨時能更換位置。
值得提醒一下的是,在這個過程中,我們要用不同顏色的貼紙區分領域行為。如下圖,我們可以用藍色表示命令,用綠色表示實體,橙色表示領域事件,黃色表示補充信息等。補充信息主要用來說明注意事項,比如外部依賴等。顏色並不固定,這只是我的習慣,團隊內統一才是重點。
3. 事件風暴的場地
什么樣的場地適合做事件風暴呢?是不是需要跟組織會議一樣,准備會議室、投影,還有椅子?這些都不需要!你只需要一堵足夠長的牆和足夠大的空間就可以了。牆是用來貼紙的,大空間可以讓人四處走動,方便合作。撤掉會議桌和椅子的事件風暴,你會發現參與者們的效率更高。
4. 事件風暴分析的關注點
在領域建模的過程中,我們需要重點關注這類業務的語言和行為。比如某些業務動作或行為(事件)是否會觸發下一個業務動作,這個動作(事件)的輸入和輸出是什么?是誰(實體)發出的什么動作(命令),觸發了這個動作(事件)…我們可以從這些暗藏的詞匯中,分析出領域模型中的事件、命令和實體等領域對象。
如何用事件風暴構建領域模型?
領域建模的過程主要包括產品願景、業務場景分析、領域建模和微服務拆分與設計這幾個重要階段。下面我以用戶中台為例,介紹一下如何用事件風暴構建領域模型。
1. 產品願景
產品願景的主要目的是對產品頂層價值的設計,使產品目標用戶、核心價值、差異化競爭點等信息達成一致,避免產品偏離方向。
產品願景的參與角色:領域專家、業務需求方、產品經理、項目經理和開發經理。
在建模之前,項目團隊要思考這樣兩點:
用戶中台到底能夠做什么?
它的業務范圍、目標用戶、核心價值和願景,與其它同類產品的差異和優勢在哪里?
這個過程也是明確用戶中台建設方向和統一團隊思想的過程。參與者要對每一個點(下圖最左側列的內容)發表意見,用水筆寫在貼紙上,貼在黃色貼紙的位置。這個過程會讓參與者充分發表意見,最后會將發散的意見統一為通用語言,建立如下圖的產品願景牆。如果你的團隊的產品願景和目標已經很清晰了,那這個步驟你可以忽略。
2. 業務場景分析
場景分析是從用戶視角出發的,根據業務流程或用戶旅程,采用用例和場景分析,探索領域中的典型場景,找出領域事件、實體和命令等領域對象,支撐領域建模。事件風暴參與者要盡可能地遍歷所有業務細節,充分發表意見,不要遺漏業務要點。
場景分析的參與角色:領域專家、產品經理、需求分析人員、架構師、項目經理、開發經理和測試經理。
用戶中台有這樣三個典型的業務場景:
第一個是系統和崗位設置,設置系統中崗位的菜單權限;
第二個是用戶權限配置,為用戶建立賬戶和密碼,設置用戶崗位;
第三個是用戶登錄系統和權限校驗,生成用戶登錄和操作日志。
我們可以按照業務流程,一步一步搜尋用戶業務流程中的關鍵領域事件,比如崗位已創建,用戶已創建等事件。再找出什么行為會引起這些領域事件,這些行為可能是一個或若干個命令組合在一起產生的,比如創建用戶時,第一個命令是從公司 HR 系統中獲取用戶信息,第二個命令是根據 HR 的員工信息在用戶中台創建用戶,創建完用戶后就會產生用戶已創建的領域事件。當然這個領域事件可能會觸發下一步的操作,比如發布到郵件系統通知用戶已創建,但也可能到此就結束了,你需要根據具體情況來分析是否還有下一步的操作。
場景分析時會產生很多的命令和領域事件。我用藍色來表示命令,用橙色表示領域事件,用黃色表示補充信息,比如用戶信息數據來源於 HR 系統的說明。
3. 領域建模
領域建模時,我們會根據場景分析過程中產生的領域對象,比如命令、事件等之間關系,找出產生命令的實體,分析實體之間的依賴關系組成聚合,為聚合划定限界上下文,建立領域模型以及模型之間的依賴。領域模型利用限界上下文向上可以指導微服務設計,通過聚合向下可以指導聚合根、實體和值對象的設計。
領域建模的參與角色:領域專家、產品經理、需求分析人員、架構師、項目經理、開發經理和測試經理。
具體可以分為這樣三步。
第一步:從命令和事件中提取產生這些行為的實體。用綠色貼紙表示實體。通過分析用戶中台的命令和事件等行為數據,提取了產生這些行為的用戶、賬戶、認證票據、系統、菜單、崗位和用戶日志七個實體。
第二步:根據聚合根的管理性質從七個實體中找出聚合根,比如,用戶管理用戶相關實體以及值對象,系統可以管理與系統相關的菜單等實體等,可以找出用戶和系統等聚合根。然后根據業務依賴和業務內聚原則,將聚合根以及它關聯的實體和值對象組合為聚合,比如系統和菜單實體可以組合為“系統功能”聚合。按照上述方法,用戶中台就有了系統功能、崗位、用戶信息、用戶日志、賬戶和認證票據六個聚合。
第三步:划定限界上下文,根據上下文語義將聚合歸類。根據用戶域的上下文語境,用戶基本信息和用戶日志信息這兩個聚合共同構成用戶信息域,分別管理用戶基本信息、用戶登錄和操作日志。認證票據和賬戶這兩個聚合共同構成認證域,分別實現不同方式的登錄和認證。系統功能和崗位這兩個聚合共同構成權限域,分別實現系統和菜單管理以及系統的崗位配置。根據業務邊界,我們可以將用戶中台划分為三個限界上下文:用戶信息、認證和權限。
到這里我們就完成了用戶中台領域模型的構建了。那由於領域建模的過程中產生的領域對象實在太多了,我們可以借助表格來記錄。
4. 微服務拆分與設計
原則上一個領域模型就可以設計為一個微服務,但由於領域建模時只考慮了業務因素,沒有考慮微服務落地時的技術、團隊以及運行環境等非業務因素,因此在微服務拆分與設計時,我們不能簡單地將領域模型作為拆分微服務的唯一標准,它只能作為微服務拆分的一個重要依據。
微服務的設計還需要考慮服務的粒度、分層、邊界划分、依賴關系和集成關系。除了考慮業務職責單一外,我們還需要考慮將敏態與穩態業務的分離、非功能性需求(如彈性伸縮要求、安全性等要求)、團隊組織和溝通效率、軟件包大小以及技術異構等非業務因素。
微服務設計建議參與的角色:領域專家、產品經理、需求分析人員、架構師、項目經理、開發經理和測試經理。
用戶中台微服務設計如果不考慮非業務因素,我們完全可以按照領域模型與微服務一對一的關系來設計,將用戶中台設計為:用戶、認證和權限三個微服務。但如果用戶日志數據量巨大,大到需要采用大數據技術來實現,這時用戶信息聚合與用戶日志聚合就會有技術異構。雖然在領域建模時,我們將他們放在一個了領域模型內,但如果考慮技術異構,這兩個聚合就不適合放到同一個微服務里了。我們可以以聚合作為拆分單位,將用戶基本信息管理和用戶日志管理拆分為兩個技術異構的微服務,分別用不同的技術來實現它們。
總結
今天我們講了事件風暴的設計方法以及如何用事件風暴來構建領域模型。事件風暴是一種不同於傳統需求分析和系統設計的方法,最好的學習方法就是找幾個業務場景多做幾次。
一般來說一個中型規模的項目,領域建模的時間大概在兩周左右,這與我們傳統的需求分析和系統設計的時間基本差不多。但是如果在領域建模的過程中,團隊成員全員參與,在項目開發之前就建立了共同語言,這對於后續的微服務設計與開發是很有幫助的,時間成本也可以視情況降低。
很多開發人員在初次學習 DDD 時,似乎並不太關心領域建模,而只是想學學 DDD 的戰術設計思想,快速上手,開發微服務。我想這是對 DDD 的一個誤解,這已經偏離了 DDD 的核心設計思想,即先有邊界清晰的領域模型,才能設計出清晰的微服務邊界,這兩個階段一前一后是剛需,我們不能忽略。