幾年前我總結過DDD戰術設計的一些可落地的經驗,現在回過頭來發現,當初對這些概念的理解還是沒有到位。比如戰術設計的各個模塊是如協作的。哪些是問題空間問題,哪些是解方案空間問題 這篇文章重新闡述下。 ...
背景
幾年前我總結過DDD戰術設計的一些落地經驗可落地的DDD(5)-戰術設計,和一次關於聚合根的激烈討論最近兩年有些新的落地體驗,回過頭來發現,當初對這些概念的理解還是沒有深入,這篇文章重新闡述下。
之前理解不到位的點有
- 戰術設計的各個模塊是的協作關係
- 哪些是問題空間問題,哪些是方案空間問題邊界沒有劃分清楚。
- 實體和聚合根的區別理解不不深刻,實體和聚合根建模的方法不對。
以上問題將會在下文解釋清楚。
戰術設計拆解
DDD的戰術設計即設計某個子域的領域模型以及代碼落地。領域事件、領域對象、聚合根、實體、值對象、領域服務、工廠、資源庫等這些概念都屬於這個範疇。
筆者將這些概念重新分層組裝了下,如下圖所示。
首先將整體分成兩部分,問題空間和方案空間。
- 問題空間即領域建模。是對業務問題的描述,以及我們如何對這些問題進行抽象。這些是需要在業務、產品、開發都必須達成一致的,與具體的技術方案無關。
- 方案空間即如何用技術手段來解決問題,與具體技術的實現有關。
問題空間即領域建模,是通過實體、值對象、領域服務、領域事件來表達。
-
實體和值對象是模型對象,實體是重中之重,包括核心模型數據、行為、狀態。之所以要區分實體和值對象,是為了降低複雜度,因為值對象是個常數對象,不需要花太多精力。
註意某個對象在某個領域內是個值對象,在另外的領域可能是個實體,所以脫離領域上下文,說某個對象是值對象,肯定是不對的,比如大家常說的地址是個值對象,這一定是對的嗎? -
領域事件即實體產生的事件
-
領域服務包括一些邏輯的計算,和業務策略。比如商業決策邏輯、業務流程等。
方案空間即如何解決問題,實現領域模型與代碼的映射。實現設計與實現的一致性。主要通過工廠,聚合,資源庫來表達。
-
聚合是對實體、值對象的封裝。領域外部對領域對象所有訪問都基於聚合來。如基礎設施層操作聚合進行數據保存。其他領域引用聚合對象數據。
聚合的設計一般是圍繞著技術來的,比如聚合對象事務性。 -
工廠,複雜對象的創建工廠類
-
資源庫,對聚合的操作。
從筆者的實踐角度來說,落地DDD過程中,問題空間比方案空間更重要,收益更大。因為通常我們吐槽的某些代碼寫的爛,貧血模型。背後並不是因為沒有用DDD,而是問題空間沒有定義好,對於業務沒有深刻理解,導致模型抽象不足。
如何建模
為什麼要建模
通常在某個子域落地DDD,我們會按照業務分析-》用例分析-》領域建模(問題空間) -》技術落地(方案空間)這些步驟來操作。但其實即使我們不在代碼里落地DDD,只用前面3步維護一個子域內的領域模型也同樣能夠帶來很多收益,包括但不限於
- 統一業務組各個角色的認知,業務、產品、開發大家對同一概念的認知是一致的。
- 指導開發工作的拆分。
比如在淘寶有個血的教訓,至今這個歷史債還無法被修複。早期在淘寶開店。一個賣家只能開一個店。賣家和店鋪是兩個領域對象,關係是1:1。店鋪服務覺得是1:1的關係,對外提供的服務有根據sellerId獲取店鋪信息,所以其他調用方就無意識的直接引用了賣家id,這樣也可以拿到店鋪。導致shopId被等同於了sellerID。這個誤引用發生在成千上萬個地方,最後導致後續需要支持一個賣家開多店鋪時無法支持。只能通過其他trick方式實現。
以之前介紹過的CRM領域 來講解。
省略業務分析,直接拿到用例。
用例分析
按用戶角色羅列所有的用例,用來推導模型、以及模型之間的關係。領域模型建立好了,需要根據列出的用例來走查一遍,要確保所有的用例都能走通。完整的用例集才能推導出正確的模型,所以當有變化時,首先調整用例集,再來修改領域模型
建模
領域建模就是定義模型對象,以及模型對象之間的關聯關係。分兩步建模,第一步通過名詞找模型對象。第二步通過動詞、形容詞分析對象關聯關係
名詞
通常反覆出現的主語和賓語中的名詞就是模型對象,比如市場人員創建一個活動,活動就是一個模型對象。當然定語中出現的名詞也可能是模型對象。
1.名詞的定義一定要清晰。比如說crm領域有通用的名詞叫商機。但是你對口的產品經理不熟悉crm領域,新造了一個詞,那你要及早糾正他。
2.名詞的含義在限界上下文內語義唯一,在不同的上下文中概念就不一定一樣了。比如市場人員創建的活動,和做營銷時創建的活動就不一定。
動詞、活動
1個市場人員可以創建多個活動,所以市場人員和活動關聯關係是1對多。兩者獨立存在,普通關聯關係。
這裡為了簡化描述,只列了市場活動、線索、客戶、商機這些域。用戶、角色、許可權、數據分析這些域先忽略了。
產出物
在推導的過程中,我們是按照自底向上的方式推導的,最後我們呈現出來的結果是按照如下方式
- 領功能變數名稱詞
市場活動: 市場人員為了展示公司形象、推廣公司產品,獲取線索而舉辦的活動。一個活動中可以創建多個線索。
線索: 銷售人員基於線索發掘潛在客戶,多個線索轉換為一個客戶。線索可以由一個市場活動生成,或者其他渠道。
客戶:有意向購買公司產品的用戶,銷售人員可以通過跟進客戶,轉化銷售機會。
銷售機會:更高質量的線索,有機會簽單。可以通過客戶轉換得到,也可以通過其他渠道來獲取
-
領域模型
如上圖 -
主要領域狀態轉換。
因為複雜的領域對象生命周期以及一些跨領域對象交互情況在領域模型圖中表達不出來,所以需要藉助額外的圖來表達。