長文圖解DDD建模六個問題與六個步驟

歡迎你們關注公衆號「JAVA前線」查看更多精彩分享文章,主要包括源碼分析、實際應用、架構思惟、職場分享、產品思考等等,同時歡迎你們加我微信「java_front」一塊兒交流學習java


0 文章概述

領域驅動設計DDD是一段時間以來比較流行的概念,可是在使用時以爲概念不少難以落地。本文就來探討DDD落地時須要關注的六個問題,並經過一個足球運動員信息管理系統案例分析落地的六個步驟。數據庫

1 六個問題

1.1 爲何使用

DDD方法論的核心是將問題不斷分解,把大問題分解爲小問題,大業務分解小領域,簡而言之就是分而治之,各個擊破。設計模式

分而治之是指直接面對大業務咱們無從下手,須要按照必定方法進行分解,分解爲高內聚的小領域,使得業務有邊界清晰,而這些小領域是咱們有能力處理的,這就是領域驅動設計的核心。緩存

各個擊破是指當問題被拆分爲小領域後,由於小領域業務內聚,其子領域高度相關,咱們在技術維度能夠對其進行詳細設計,在管理維度能夠按照領域對項目進行分工。須要指出DDD不能替代詳細設計,DDD是爲了更清晰地行詳細設計。微信

在微服務流行的互聯網行業,當業務逐漸複雜時,技術人員須要解決如何劃分微服務邊界的問題,DDD這種清晰化業務邊界的特性正好能夠用來解決這個問題。markdown


1.2 方法與目標

咱們的目標是將業務劃分清晰的邊界,而DDD是達成目標的有效方法之一,這一點是須要格外注意的。DDD是方法不是目標,不須要爲了使用而使用。例如業務模型比較簡單能夠很容易分析的業務就不須要使用DDD,還有一些目標是快速驗證類型的項目,追求短平快,前期可能也不須要使用領域驅動設計。數據結構


1.3 總體與局部

領域能夠劃分多個子領域,子域能夠再劃分多個子子域,限界上下文本質上也是一種子子域,那麼在業務分解時一個業務模塊究竟是領域、子域仍是子子域?架構

我認爲不用糾結在這個問題,由於這取決於看待這個模塊的角度。你認爲總體多是別人的局部,你認爲的局部多是別人的總體,叫什麼名字不重要,最重要的是按照高內聚的原則將業務高度相關的模塊收斂在一塊兒。框架


1.4 粒度粗與細

業務劃分粒度的粗細並無統一的標準,仍是要根據業務須要、開發資源、技術實力等因素綜合考量。例如微服務拆分過細反而會增長開發、部署和維護的複雜度,可是拆分過粗可能會致使大量業務高度耦合,開發部署起來是挺快的,可是缺失可維護性和可擴展性,這須要根據實際狀況作出權衡。dom


1.5 領域與數據

領域對象與數據對象一個重要的區別是值對象存儲方式。在討論領域對象和數據對象以前,咱們首先討論實體和值對象這一組概念。實體是具備惟一標識的對象,而惟一標識會伴隨實體對象整個生命週期而且不可變動。值對象本質上是屬性的集合,並無惟一標識。

領域對象在包含值對象的同時也保留了值對象的業務含義,而數據對象可使用更加鬆散的結構保存值對象,簡化數據庫設計。

如今假設咱們須要管理足球運動員信息,對應的領域模型和數據模型應該如何設計?姓名、身高、體重是一名運動員本質屬性,加上惟一編號能夠對應實體對象。跑動距離,傳球成功率,進球數是運動員比賽中的表現,這些屬性的集合能夠對應值對象。

值對象在數據對象中能夠用鬆散的數據結構進行存儲,而值對象在領域對象中須要保留其業務含義:

根據圖示編寫領域對象與數據對象代碼:

// 數據對象
public class FootballPlayerDO {
    private Long id;
    private String name;
    private Integer height;
    private Integer weight;
    private String gamePerformance;
}

// 領域對象
public class FootballPlayerDMO {
    private Long id;
    private String name;
    private Integer height;
    private Integer weight;
    private GamePerformanceVO gamePerformanceVO;
}

public class GamePerformanceVO {
    private Double runDistance;
    private Double passSuccess;
    private Integer scoreNum;
}
複製代碼

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核心是分而治之各個擊破,並配合一些通過檢驗的有效方法進行建模,但願本文對你們有所幫助。


歡迎你們關注公衆號「JAVA前線」查看更多精彩分享文章,主要包括源碼分析、實際應用、架構思惟、職場分享、產品思考等等,同時歡迎你們加我微信「java_front」一塊兒交流學習

相關文章
相關標籤/搜索