領域模型驅動設計筆記

通用語言

 

內聚機制

機制性的如何做,有時候會掩蓋掉做什麼。core domain和generic subdomain表達的是事實、規則或問題,而內聚機制是滿足這些規則和完成模型指定的計算。機制和模型分開。

subdomain和內聚機制的動機,都是爲core model減負。

核心域VS子域

 

 

貧血型模型

我的業務邏輯都是寫在Service中的,模型充其量只是個數據載體,沒有任何行爲。簡單的業務系統採用這種貧血模型和過程化設計是沒有問題的,但在業務邏輯複雜了,業務邏輯、狀態會散落到在大量方法中,原本的代碼意圖會漸漸不明確,我們將這種情況稱爲由貧血症引起的失憶症。更好的是採用領域模型的開發方式,將數據和行爲封裝在一起,並與現實世界中的業務對象相映射。

架構設計

微服務架構更強調從業務維度去做分治來應對系統複雜度,而DDD也是同樣的着重業務視角。 如果兩者在追求的目標(業務維度)達到了上下文的統一,那麼在具體做法上有什麼聯繫和不同呢?

我們將架構設計活動精簡爲以下三個層面:

  • 業務架構——根據業務需求設計業務模塊及其關係
  • 系統架構——設計系統和子系統的模塊
  • 技術架構——決定採用的技術及框架

以上三種活動在實際開發中是有先後順序的,但不一定孰先孰後。在我們解決常規套路問題時,我們會很自然地往熟悉的分層架構套(先確定系統架構),或者用PHP開發很快(先確定技術架構),在業務不復雜時,這樣是合理的。

跳過業務架構設計出來的架構關注點不在業務響應上,可能就是個大泥球,在面臨需求迭代或響應市場變化時就很痛苦。

DDD的核心訴求就是將業務架構映射到系統架構上,在響應業務變化調整業務架構時,也隨之變化系統架構。而微服務追求業務層面的複用,設計出來的系統架構和業務一致;在技術架構上則系統模塊之間充分解耦,可以自由地選擇合適的技術架構,去中心化地治理技術和數據。

兩者的區別:

DDDä¸å¾®æå¡å³ç³»

領域

現實世界中,領域包含了問題域和解系統。一般認爲軟件是對現實世界的部分模擬。在DDD中,解系統可以映射爲一個個限界上下文,限界上下文就是軟件對於問題域的一個特定的、有限的解決方案。

限界上下文

一個由顯示邊界限定的特定職責。領域模型便存在於這個邊界之內。在邊界內,每一個模型概念,包括它的屬性和操作,都具有特殊的含義。

一個給定的業務領域會包含多個限界上下文,想與一個限界上下文溝通,則需要通過顯示邊界進行通信。系統通過確定的限界上下文來進行解耦,而每一個上下文內部緊密組織,職責明確,具有較高的內聚性。

一個很形象的隱喻:細胞質所以能夠存在,是因爲細胞膜限定了什麼在細胞內,什麼在細胞外,並且確定了什麼物質可以通過細胞膜。

劃分限界上下文

顯然我們不應該按技術架構或者開發任務來創建限界上下文,應該按照語義的邊界來考慮。

- 從需求出發,按領域劃分

- 按照語義的邊界來考慮

我們的實踐是,考慮產品所講的通用語言,從中提取一些術語稱之爲概念對象,尋找對象之間的聯繫;或者從需求裏提取一些動詞,觀察動詞和對象之間的關係;我們將緊耦合的各自圈在一起,觀察他們內在的聯繫,從而形成對應的界限上下文。形成之後,我們可以嘗試用語言來描述下界限上下文的職責,看它是否清晰、準確、簡潔和完整。簡言之,限界上下文應該從需求出發,按領域劃分。

前文提到,我們的用戶劃分爲運營和用戶。其中,運營對抽獎活動的配置十分複雜但相對低頻。用戶對這些抽獎活動配置的使用是高頻次且無感知的。根據這樣的業務特點,我們首先將抽獎平臺劃分爲C端抽獎和M端抽獎管理平臺兩個子域,讓兩者完全解耦。

抽獎平臺領域

抽獎平臺領域

在確認了M端領域和C端的限界上下文後,我們再對各自上下文內部進行限界上下文的劃分。下面我們用C端進行舉例。

產品的需求概述如下:

1. 抽獎活動有活動限制,例如用戶的抽獎次數限制,抽獎的開始和結束的時間等;
2. 一個抽獎活動包含多個獎品,可以針對一個或多個用戶羣體;
3. 獎品有自身的獎品配置,例如庫存量,被抽中的概率等,最多被一個用戶抽中的次數等等;
4. 用戶羣體有多種區別方式,如按照用戶所在城市區分,按照新老客區分等;
5. 活動具有風控配置,能夠限制用戶參與抽獎的頻率。

根據產品的需求,我們提取了一些關鍵性的概念作爲子域,形成我們的限界上下文。

C端抽獎領域

C端抽獎領域

首先,抽獎上下文作爲整個領域的核心,承擔着用戶抽獎的核心業務,抽獎中包含了獎品和用戶羣體的概念。

  • 在設計初期,我們曾經考慮劃分出抽獎和發獎兩個領域,前者負責選獎,後者負責將選中的獎品發放出去。但在實際開發過程中,我們發現這兩部分的邏輯緊密連接,難以拆分。並且單純的發獎邏輯足夠簡單,僅僅是調用第三方服務進行發獎,不足以獨立出來成爲一個領域。

對於活動的限制,我們定義了活動准入的通用語言,將活動開始/結束時間,活動可參與次數等限制條件都收攏到活動准入上下文中。

對於抽獎的獎品庫存量,由於庫存的行爲與獎品本身相對解耦,庫存關注點更多是庫存內容的核銷,且庫存本身具備通用性,可以被獎品之外的內容使用,因此我們定義了獨立的庫存上下文。

由於C端存在一些刷單行爲,我們根據產品需求定義了風控上下文,用於對活動進行風控。 最後,活動准入、風控、抽獎等領域都涉及到一些次數的限制,因此我們定義了計數上下文。

可以看到,通過DDD的限界上下文劃分,我們界定出抽獎、活動准入、風控、計數、庫存等五個上下文,每個上下文在系統中都高度內聚。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章