十張圖講清楚ddd建模六個問題與六個步驟如下:
1 六個問題
1.1 為什麽使用
DDD方法論的核心是將問題不斷分解,把大問題分解為小問題,大業務分解小領域,簡而言之就是分而治之,各個擊破。
分而治之是指直接面對大業務我們無從下手,需要按照壹定方法進行分解,分解為高內聚的小領域,使得業務有邊界清晰,而這些小領域是我們有能力處理的,這就是領域驅動設計的核心。
各個擊破是指當問題被拆分為小領域後,因為小領域業務內聚,其子領域高度相關,我們在技術維度可以對其進行詳細設計,在管理維度可以按照領域對項目進行分工。需要指出DDD不能替代詳細設計,DDD是為了更清晰地詳細設計。
在微服務流行的互聯網行業,當業務逐漸復雜時,技術人員需要解決如何劃分微服務邊界的問題,DDD這種清晰化業務邊界的特性正好可以用來解決這個問題。
1.2 方法與目標
我們的目標是將業務劃分清晰的邊界,而DDD是達成目標的有效方法之壹,這壹點是需要格外註意的。DDD是方法不是目標,不需要為了使用而使用。
例如業務模型比較簡單可以很容易分析的業務就不需要使用DDD,還有壹些目標是快速驗證類型的項目,追求短平快,前期可能也不需要使用領域驅動設計。
1.3 整體與局部
領域可以劃分多個子領域,子域可以再劃分多個子子域,限界上下文本質上也是壹種子子域,那麽在業務分解時壹個業務模塊到底是領域、子域還是子子域?
我認為不用糾結在這個問題,因為這取決於看待這個模塊的角度。妳認為整體可能是別人的局部,妳認為的局部可能是別人的整體,叫什麽名字不重要,最重要的是按照高內聚的原則將業務高度相關的模塊收斂在壹起。
1.4 粒度粗與細
業務劃分粒度的粗細並沒有統壹的標準,還是要根據業務需要、開發資源、技術實力等因素綜合考量。例如微服務拆分過細反而會增加開發、部署和維護的復雜度。
但是拆分過粗可能會導致大量業務高度耦合,開發部署起來是挺快的,但是缺失可維護性和可擴展性,這需要根據實際情況做出權衡。
1.5 領域與數據
領域對象與數據對象壹個重要的區別是值對象存儲方式。在討論領域對象和數據對象之前,我們首先討論實體和值對象這壹組概念。實體是具有唯壹標識的對象,而唯壹標識會伴隨實體對象整個生命周期並且不可變更。值對象本質上是屬性的集合,並沒有唯壹標識。
領域對象在包含值對象的同時也保留了值對象的業務含義,而數據對象可以使用更加松散的結構保存值對象,簡化數據庫設計。
現在假設我們需要管理足球運動員信息,對應的領域模型和數據模型應該如何設計?姓名、身高、體重是壹名運動員本質屬性,加上唯壹編號可以對應實體對象。跑動距離,傳球成功率,進球數是運動員比賽中的表現,這些屬性的集合可以對應值對象。
值對象在數據對象中可以用松散的數據結構進行存儲,而值對象在領域對象中需要保留其業務含義。
1.6 抽象與靈活
抽象的核心是找相同,對不同事物提取公因式。實現的核心是找不同,擴展各自的屬性和特點。例如模板方法設計模式正是用抽象構建框架,用實現擴展細節。
我們再回到數據模型的討論,可以發現腳本化是壹種拓展靈活性的方式,腳本化不僅指使用groovy、QLExpress腳本增強系統靈活性,還包括松散可擴展的數據結構。
數據模型抽象出了姓名、身高、體重這些基本屬性,對於頻繁變化的比賽表現屬性,這些屬性值可能經常變化,甚至屬性本身也是經常變化,例如可能會加上射門次數,突破次數等,所以采用松散的JSON數據結構進行存儲。
2 六個步驟
工程理論總是要落地的,落地也是需要壹些步驟和方法的。本文我們壹起分析壹個足球運動員信息管理系統,目標是管理運動員從轉會到上場比賽整條鏈路信息,這個系統大家應該也都沒有接觸過,我們壹起來分析。
需要說明本實例著重演示DDD方法論如何落地,業務細節可能並不能面面俱到。
2.1 流程梳理
梳理流程有兩個問題需要考慮,第壹個問題是從什麽視角去梳理?因為不同的人看到的流程是不壹樣的。答案是取決於系統需要解決的是什麽問題,因為我們要管理運動員從轉會到上場比賽整條鏈路信息,所以從運動員視角出發是壹個合適的選擇。
第二個問題是對業務不熟悉怎麽辦?因為我們不是體育和運動專家,並不清楚整條鏈路的業務細節。
答案是梳理流程時壹定要有業務專家在場,因為沒有真實業務細節,無法領域驅動設計。同理在互聯網梳理復雜業務流程時,壹定要有對相關業務熟悉的產品經理或者運營壹起參與。
假設足球業務專家梳理出了業務流程,運動員提出轉會,協商壹致後到新俱樂部體檢,體檢通過就進行簽約。進入新俱樂部後進行訓練,訓練指標達標後上場比賽,賽後參加新聞發布會。
2.2 四色建模
(1) 時標對象
四色建模第壹種顏色是紅色,表示時標對象。時標對象是四色建模最重要的對象,可以理解為核心業務單據。在業務進行過程中壹定要對關鍵業務留下單據,通過這些單據可以追溯出整個業務流程。
時標對象具有兩個特點:第壹是事實不可變性,記錄了過去某個時間點或時間段內發生的事實。第二是責任可追溯性,記錄了管理者關註的信息。現在我們分析本系統時標對象有哪些,需要留下哪些核心業務單據。
轉會對應轉會單據,體檢對應體檢單據,簽合同對應合同單據,訓練對應訓練指標單據,比賽對應比賽指標單據,新聞發布會對應采訪單據。根據分析繪制如下時標對象:
(2) 參與方、地、物
這三類對象在四色建模中用綠色表示,我們以電商場景為例進行說明。用戶支付購買商家的商品時,用戶和商家是參與方。物流系統發貨時配送單據需要有配送地址對象,地址對象就是地。訂單需要商品對象,物流配送需要有貨品,商品和貨品就是物。
我們分析本例得到「參與方」包含總經理、隊醫、教練、球迷、記者,「地」包括訓練地址、比賽地址、采訪地址,「物」包含簽名球衣和簽名足球。
(3) 角色對象
在四色建模中用黃色表示,這類對象表示參與方、地、物是以什麽角色參與到業務流程。
(4) 描述對象
增加對象相關描述信息,在四色建模法用藍色表示。
2.3 劃分領域
在四色建模過程中我們體會到時標對象是最重要的對象,因為其承載了業務系統核心單據。在劃分領域時我們同樣離不開時標對象,核心是通過收斂相關時標對象劃分業務領域。
2.4 領域事件
當業務系統發生壹件事情時,如果本領域或其它領域有後續動作跟進,那麽我們把這件事情稱為領域事件,這個事件需要被感知。
例如球員比賽受傷了,這是比賽子域事件,但是醫療和訓練子域是需要感知的,那麽比賽子域就發出壹個事件,醫療和訓練子域會訂閱。
例如球員比賽取得進球,這也是比賽子域事件,但是訓練和合同子域也會關註這個事件,那麽比賽子域也會發出壹個事件,訓練和合同子域會訂閱。
通過事件交互有壹個問題需要註意,通過事件訂閱實現業務只能采用最終壹致性,需要放棄強壹致性,這壹點可能會引入新的復雜度需要權衡。
2.5 項目搭建
(1) API
接口層:提供面向外部接口聲明和DTO對象
(2) controller
訪問層:提供HTTP訪問入口
(3) service
業務層:領域層和業務層都包含業務,但是用途不同。業務層可以組合不同領域業務,並且可以增加流控、監控、日誌、權限控制切面,相較於領域層更為豐富,提供BO對象
(4) domain
領域層:提供DMO(DomainObject)、VO、事件、數據訪問對象,核心是按照領域進行分包,領域內高內聚,領域間低耦合
(5) dependency
外部訪問層:在這個模塊中調用外部RPC服務,解析返回碼和返回數據
(6) infrastructure
基礎層:包含基礎功能,例如緩存工具,消息隊列,分布式鎖,消息發送等功能
我們展開分析領域層,核心是按照領域進行分包,並且提供DMO、VO、事件、數據訪問對象,領域內高內聚,領域間低耦合,例如domain1對應合同子域,domain2對應訓練子域。
2.6 詳細設計
目前為止領域已經確定了,現在可以劃分任務了,組內成員分別負責壹個或多個領域進行詳細設計,這個階段就是大家熟悉的用例圖,活動圖,時序圖,數據庫設計,接口設計的用武之地。需要說明領域驅動設計不是取代詳細設計,而是為了更清晰地詳細設計。
3 文章總結
本文探討了DDD落地時需要關註的六個問題,並通過壹個足球運動員信息管理系統案例分析落地的六個步驟。在實際應用中各業務形態可能千差萬別,但是方法論卻可以通用,我們需要明確DDD核心是分而治之各個擊破,並配合壹些經過檢驗的有效方法進行建模,希望本文對大家有所幫助。
————————————————
版權聲明:本文為CSDN博主「JAVA前線」的原創文章,遵循CC 4.0 BY-SA版權協議,轉載請附上原文出處鏈接及本聲明。