可落地的DDD(7)-戰術設計上的一些誤區

2022-07-15 12:00:27

背景

幾年前我總結過DDD戰術設計的一些落地經驗可落地的DDD(5)-戰術設計,和一次關於聚合根的激烈討論最近兩年有些新的落地體驗,回過頭來發現,當初對這些概念的理解還是沒有深入,這篇文章重新闡述下。

之前理解不到位的點有

  1. 戰術設計的各個模組是的共同作業關係
  2. 哪些是問題空間問題,哪些是方案空間問題邊界沒有劃分清楚。
  3. 實體和聚合根的區別理解不不深刻,實體和聚合根建模的方法不對。

以上問題將會在下文解釋清楚。

戰術設計拆解

DDD的戰術設計即設計某個子域的領域模型以及程式碼落地。領域事件、領域物件、聚合根、實體、值物件、領域服務、工廠、資源庫等這些概念都屬於這個範疇。

筆者將這些概念重新分層組裝了下,如下圖所示。


首先將整體分成兩部分,問題空間和方案空間。

  1. 問題空間即領域建模。是對業務問題的描述,以及我們如何對這些問題進行抽象。這些是需要在業務、產品、開發都必須達成一致的,與具體的技術方案無關。
  2. 方案空間即如何用技術手段來解決問題,與具體技術的實現有關。

問題空間即領域建模,是通過實體、值物件、領域服務、領域事件來表達。

  1. 實體和值物件是模型物件,實體是重中之重,包括核心模型資料、行為、狀態。之所以要區分實體和值物件,是為了降低複雜度,因為值物件是個常數物件,不需要花太多精力。
    注意某個物件在某個領域內是個值物件,在另外的領域可能是個實體,所以脫離領域上下文,說某個物件是值物件,肯定是不對的,比如大家常說的地址是個值物件,這一定是對的嗎?

  2. 領域事件即實體產生的事件

  3. 領域服務包括一些邏輯的計算,和業務策略。比如商業決策邏輯、業務流程等。

方案空間即如何解決問題,實現領域模型與程式碼的對映。實現設計與實現的一致性。主要通過工廠,聚合,資源庫來表達。

  1. 聚合是對實體、值物件的封裝。領域外部對領域物件所有存取都基於聚合來。如基礎設施層操作聚合進行資料儲存。其他領域參照聚合物件資料。
    聚合的設計一般是圍繞著技術來的,比如聚合物件事務性。

  2. 工廠,複雜物件的建立工廠類

  3. 資源庫,對聚合的操作。

從筆者的實踐角度來說,落地DDD過程中,問題空間比方案空間更重要,收益更大。因為通常我們吐槽的某些程式碼寫的爛,貧血模型。背後並不是因為沒有用DDD,而是問題空間沒有定義好,對於業務沒有深刻理解,導致模型抽象不足。

如何建模

為什麼要建模

通常在某個子域落地DDD,我們會按照業務分析-》用例分析-》領域建模(問題空間) -》技術落地(方案空間)這些步驟來操作。但其實即使我們不在程式碼裡落地DDD,只用前面3步維護一個子域內的領域模型也同樣能夠帶來很多收益,包括但不限於

  1. 統一業務組各個角色的認知,業務、產品、開發大家對同一概念的認知是一致的。
  2. 指導開發工作的拆分。

比如在淘寶有個血的教訓,至今這個歷史債還無法被修復。早期在淘寶開店。一個賣家只能開一個店。賣家和店鋪是兩個領域物件,關係是1:1。店鋪服務覺得是1:1的關係,對外提供的服務有根據sellerId獲取店鋪資訊,所以其他呼叫方就無意識的直接參照了賣家id,這樣也可以拿到店鋪。導致shopId被等同於了sellerID。這個誤參照發生在成千上萬個地方,最後導致後續需要支援一個賣家開多店鋪時無法支援。只能通過其他trick方式實現。

以之前介紹過的CRM領域 來講解。
省略業務分析,直接拿到用例。

用例分析


按使用者角色羅列所有的用例,用來推導模型、以及模型之間的關係。領域模型建立好了,需要根據列出的用例來走查一遍,要確保所有的用例都能走通。完整的用例集才能推匯出正確的模型,所以當有變化時,首先調整用例集,再來修改領域模型

建模

領域建模就是定義模型物件,以及模型物件之間的關聯關係。分兩步建模,第一步通過名詞找模型物件。第二步通過動詞、形容詞分析物件關聯關係

名詞

通常反覆出現的主語和賓語中的名詞就是模型物件,比如市場人員建立一個活動,活動就是一個模型物件。當然定語中出現的名詞也可能是模型物件。

1.名詞的定義一定要清晰。比如說crm領域有通用的名詞叫商機。但是你對口的產品經理不熟悉crm領域,新造了一個詞,那你要及早糾正他。

2.名詞的含義在限界上下文內語意唯一,在不同的上下文中概念就不一定一樣了。比如市場人員建立的活動,和做行銷時建立的活動就不一定。

動詞、活動

1個市場人員可以建立多個活動,所以市場人員和活動關聯關係是1對多。兩者獨立存在,普通關聯關係。

這裡為了簡化描述,只列了市場活動、線索、客戶、商機這些域。使用者、角色、許可權、資料分析這些域先忽略了。

產出物

在推導的過程中,我們是按照自底向上的方式推導的,最後我們呈現出來的結果是按照如下方式

  1. 領域名詞
    市場活動: 市場人員為了展示公司形象、推廣公司產品,獲取線索而舉辦的活動。一個活動中可以建立多個線索。

線索: 銷售人員基於線索發掘潛在客戶,多個線索轉換為一個客戶。線索可以由一個市場活動生成,或者其他渠道。

客戶:有意向購買公司產品的使用者,銷售人員可以通過跟進客戶,轉化銷售機會。

銷售機會:更高質量的線索,有機會簽單。可以通過客戶轉換得到,也可以通過其他渠道來獲取

  1. 領域模型
    如上圖

  2. 主要領域狀態轉換。
    因為複雜的領域物件生命週期以及一些跨領域物件互動情況在領域模型圖中表達不出來,所以需要藉助額外的圖來表達。