DDD學習筆記(基礎)

1. 爲何須要DDD,解決了什麼問題

image.png

當前軟件架構模式的演進三階段:

  1. 單機架構(面向過程,2層架構)
  2. 集中式架構(面向對象,3層架構或SOA架構)
  3. 分佈式微服務架構
  • 存在的問題
    單機和集中式架構問題在於系統分析設計和開發是獨立、分階段割裂進行,容易信息丟失、上線後需求誤差大,沒法快速響應需求和業務的迅速變化
    微服務解決了擴展性、彈性伸縮能力、小規模團隊的敏捷開發等等,但微服務須要注意切割的粒度多大、如何拆分設計、邊界如何規定等問題,處理很差時會致使拆分過分致使項目複雜度高,沒法上線和運維的困境
    其中根本緣由在於不知道業務或者微服務的邊界到底在哪裏致使,而DDD就很好的指導人們怎麼去解決這個問題

DDD(領域驅動設計):

  1. 核心思想是經過領域驅動設計方法定義領域模型,從而肯定業務和應用邊界,保證業務模型和代碼模型的一致性(「高內聚、低耦合」)
  2. 一種處理高度複雜領域的設計思想,分離技術實現的複雜性,並圍繞業務概念構建領域模型來控制業務的複雜性,以解決軟件難以理解、難以演進的問題。
  3. 一種架構設計方法論,戰略設計(業務視角)和戰術設計(技術視角)兩部分數據庫

    • 戰略設計從業務視角出發,創建業務領域模型、劃分領域邊界、創建通用語言的限界上下文、限界上下文能夠做爲微服務設計的參考邊界
    • 戰術設計從技術角度出發,側重於領域模型的技術實現,完成軟件開發和落地,包括:聚合根、實體、值對象、領域服務、應用服務和資源庫等代碼邏輯的設計和實現

如何進行戰略設計:

image.png

  1. 優先創建領域模型架構

    1. 領域模型用於指導微服務的設計和拆分
    2. 事件風暴是創建領域模型的主要方法,它是一個從發散到收斂的過程併發

      • 發散過程:採用用例分析、場景分析、用戶旅程分析,儘量全面不遺漏地分解業務領域,並梳理領域對象之間的關係
      • 收斂的過程:過程當中產生不少的實體、命令、事件等領域對象、咱們將這些領域對象從不一樣的維度進行聚類,造成聚合、限界上下文等邊界,創建領域模型
  2. 三步劃定領域模型和微服務邊界運維

    1. 事件風暴中梳理業務過程當中的用戶操做、事件以及外部依賴關係等,根據這些要素梳理出領域實體等領域對象
    2. 根據領域實體之間的業務關聯性,將業務緊密相關的實體進行組合造成聚合,同時肯定聚合中的聚合根、值對象和實體。聚合之間的邊界是第一層邊界,它們在同一個微服務實例中運行,這個邊界是邏輯邊界,因此用虛線表示
    3. 根據業務及語義邊界等因素、將一個或者多個聚合劃定在一個限界上下文內,造成領域模型。限界上下文之間的邊界是第二層邊界,這一層邊界可能就是將來微服務的邊界,不一樣限界下下文內的領域邏輯被隔離在不一樣的微服務實例中運行,物理上互相隔離,因此是物理邊界,邊界之間用實線表示
有兩層邊界、微服務的設計就不是難事了(吐槽:難的是要分出這兩層邊界先阿!)
  1. 戰略到戰術設計的實施過程當中(落地過程當中)異步

    • 將領域模型中的領域對象與代碼模型中的代碼對象創建映射關係,
    • 將業務架構和系統架構進行綁定
    • 當咱們去響應業務變化調整業務架構和領域模型時,系統架構也會同時發生調整,並同步創建新的映射關係。

DDD與微服務

  1. 不一樣定位數據庫設計

    • DDD是架構設計方法
    • 微服務是架構風格
  2. 共同目標分佈式

    • 追求高響應力,從業務視角去分離應用系統建設複雜度的手段
    • 強調業務觸發,其核心要義是強調根據業務發展,合理劃分領域邊界,持續調整現有架構,優化現有代碼,以保持架構和代碼的生命力
  3. 不一樣關注微服務

    • DDD關注:從業務領域視角劃分領域邊界,構建通用語言進行高效溝通,經過業務抽象,創建領域模型,維持業務和代碼的邏輯一致性
    • 微服務關注:運行是的進程間通訊、容錯和故障隔離,實現去中心化數據管理和去中心化服務治理,關注微服務的獨立開發、測試、構建和部署
DDD不只能夠用於微服務設計,還能夠很好地應用於企業中臺的設計

DDD運用難點

DDD 戰術設計對設計和開發人員的要求相對較高,實現起來相對複雜。
不一樣企業的研發管理能力和我的開發水平可能會存在差別。
尤爲對於傳統企業而言,在戰術設計落地的過程當中,可能會存在必定挑戰和困難,我建議你和你的公司若是有這方面的想法,就必定要謹慎評估本身的能力,選擇最合適的方法落地 DDD。

DDD的收穫總結

  1. DDD 是一套完整而系統的設計方法,它能帶給你從戰略設計到戰術設計的標準設計過程,使得你的設計思路可以更加清晰,設計過程更加規範。
  2. DDD 善於處理與領域相關的擁有高複雜度業務的產品開發,經過它能夠創建一個核心而穩定的領域模型,有利於領域知識的傳遞與傳承。
  3. DDD 強調團隊與領域專家的合做,可以幫助你的團隊創建一個溝通良好的氛圍,構建一致的架構體系。
  4. DDD 的設計思想、原則與模式有助於提升你的架構設計能力。不管是在新項目中設計微服務,仍是將系統從單體架構演進到微服務,均可以遵循 DDD 的架構原則。
  5. DDD 不只適用於微服務,也適用於傳統的單體應用。

2. 有哪些元素組成

  • 概念名詞:(概念總結)性能

    名稱 簡要解釋
    領域 Domain
    子域 Sub Domain
    核心域 Core Domain
    通用域 Common Domain
    支撐域 Support Domain
    通用語言 Common Language
    限界上下文 Bounded Context
    實體 Entity
    值對象 ValueObject
    聚合 Aggregate
    聚合根 AggregateRoot
  • 參與角色:學習

    名稱
    領域專家
    產品經理
    項目經理
    架構師
    開發經理
    測試經理

3. 如何劃分領域、子域、通用域、支撐域

什麼是領域

領域:是用來肯定範圍,範圍即邊界(DDD設計中不斷強調邊界的緣由)。而在DDD中表明着這個邊界內要解決的業務問題域

整體思路

業務領域細分 -> 問題範圍限定在特定的邊界內 -> 邊界內創建領域模型 -> 代碼實現領域模型 ->解決相應業務問題

子域劃分

  1. 子領域:領域用來限定業務邊界和範圍,天然有大小之分,因此從領域可劃分子領域,每一個子域對應一個更小的問題域或更小的業務範圍
  2. 基本思路:

    1. 領域建模和微服務建設的過程和方法基本相似,其核心思想就是將問題域逐步分解,下降業務理解和系統實現的複雜度
  3. 劃分思路類比天然科學研究過程

    1. 肯定研究對象 -> 領域
    2. 對研究對象進行細分爲器官 ->問題子域
    3. 對器官進行細分爲組織 -> 再次細分子域
    4. 對組織進行細分爲細胞,細胞壁肯定了單元邊界 -> 最小邊界
  4. 子域分類:
    核心域:決定產品和公司核心競爭力的子域,業務成功的主要因素和公司的核心競爭力
    通用域:沒有太多個性化的訴求,同時被多個子域使用的通用功能子域
    支撐域:不包含決定產品和公司的核心競爭力的功能呢,也不包含通用功能的子域

4. 如何劃分限界上下文

通用語言定義上下文含義,限界上下文則定義領域邊界,以確保每一個上下文含義在他特定的邊界內都具備惟一的含義,領域模型則存在於這個邊界以內

什麼是通用語言

  1. 概念闡述

    • 在事件風暴過程當中經過團隊交流達成共識的,可以簡單、清晰、準確描述業務涵義和規則的語言就是通用語言
    • 目標解決交流障礙這個問題,是領域專家和開發人員可以協同合做,從而確保業務需求的正確表達
    • 通用語言包含屬於和用例場景,而且可以直接反應在代碼中。
    • 不一樣類型不一樣含義

      • 名詞能夠給領域對象命名,如商品、訂單等,對應實體對象
      • 動詞能夠表示一個動做或者事件,如商品已下單、訂單已付款等,對應領域事件或命令
    • 其做用貫穿DDD整個設計過程
  2. 從事件風暴創建通用語言到領域對象設計和代碼落地完整過程:

image.png

1.  經過事件風暴過程:領域專家、設計、開發人員一塊兒創建領域模型,在領域建模的過程當中會造成通用的業務術語和用戶故事。(事件風暴也是一個項目團隊統一語言的過程)
2.  經過用戶故事分析會造成一個個的領域對象,這些領域對象對應領域模型的業務對象,每一個業務對象和領域對象都有通用的名詞術語,而且一個個映射
3.  微服務代碼模型來源於領域模型,每一個代碼模型的代碼對象跟領域對象一一對應
小方法:設計過程當中能夠用一些表格來記錄事件風暴和微服務設計過程當中產生的領域對象及其屬性
  1. 要點

    • DDD分析和設計過程當中的每個環節都須要保證限界上下文內屬於的統一,在代碼模型設計的時候就要創建領域對象和代碼對象的一一映射,從而保證業務模型和代碼模型的一致,實現業務語言與代碼語言的統一

什麼是限界上下文

  1. 概念闡述

    • DDD在戰略設計上提出了限界上下文這個概念,用來肯定語義所在的領域邊界

      • 限界: 領域的邊界
      • 上下文:語義環境
    • 限界上下文就是用來封裝通用語言和領域對象,提供上下文環境,保證在領域以內的一些屬於、業務相關對象等(通用語言)有個確切的含義,沒有二義性
    • 領域邊界就是經過限界上下文來定義的,而這個邊界定義了模型的適用範圍,使團隊全部成員可以明確地知道什麼應該在模型中實現,什麼不該該在模型中實現

      • 經過領域的限界上下文,就能夠在同一的領域邊界內用同一的語言進行交流
  2. 限界上下文和微服務的關係
    將限界上下文內的領域模型映射到微服務,就完成了從問題域到軟件的解決方案

    疑惑倉儲究竟是什麼實現?

5. 如何劃分實體、值對象

什麼是實體

  1. 實體:擁有惟一標識符,且標識符在經歷各類狀態變動後仍能保持一致
  2. 形態表現

    • 業務形態:領域模型中的實體是多個屬性、操做或信用的載體;事件風暴中,根據命令、操做或者事件、找出產生這些行爲的業務實體對象、進而按照必定的業務規則將依存度高和業務關聯緊密的多個實體對象和值對象進行聚類,造成聚合。 實體和值對象是組成領域模型的基礎單元
    • 代碼形態:實體類,類包含了實體的屬性和方法,經過這些方法實現實體自身的業務邏輯。DDD裏,這些實體類一般採用充血模型,與這個實體相關的全部業務邏輯都在實體類的方法中實現,跨多個實體的領域邏輯則在領域服務中實現
    • 運行形態:DO(領域對象)的形式存在,每一個實體對象都有惟一的ID。能夠對實體對象進行屢次修改,因爲擁有相同ID,他們依然是同一個實體。
    • 數據庫形態:領域模型映射到數據模型時,一個實體可能對應0~n個數據庫持久化對象(一般爲1)

      • 用戶&角色 可組合得出 權限實體 (2個持久化對應1個實體)
      • 客戶信息&帳戶信息存同一張表 (2個實體對應1個持久化)

什麼是值對象

  1. 值對象:經過對象屬性值來識別的對象,它將多個相關屬性組合成一個概念總體,描述領域的特定方向,並一個沒有標識符的對象

    • 本質是一個集合,若干個用於描述目的、具備總體概念和不可修改的屬性
    • 存在的意義,領域建模過程當中保證屬性歸類的清晰和概念的完整性,避免屬性零碎
  2. 形態表現

    • 業務形態:基礎對象,來源於實踐風暴所構建的領域模型。

      本質上,實體是看獲得、摸得着的實實在在的業務對象,實體具備業務屬性、業務行爲和業務邏輯。而值對象只是若干個屬性的集合,只有數據初始化操做和有限的不涉及修改數據的行爲,基本不包含業務邏輯。值對象的屬性集雖然在物理上獨立出來了,但在邏輯上它仍然是實體屬性的一部分,用於描述實體的特徵。
    • 代碼形態:單一屬性時,則直接定義爲實體類的屬性,若是是屬性集合時,設計爲Class類(沒有ID)
    • 運行形態:兩種不一樣的數據格式分別屬性嵌入(1:1時,直接平鋪注入)、序列化大對象(1:n,序列化成大對象JSON串嵌入)
    • 數據庫形態:值對象的屬性值和實體對象的屬性值保存在同一個數據庫實體表中

      DDD 引入值對象是但願實現從「數據建模爲中心」向「領域建模爲中心」轉變,減小數據庫表的數量和表與表之間複雜的依賴關係,儘量地簡化數據庫設計,提高數據庫性能。
      在領域建模時,咱們能夠將部分對象設計爲值對象,保留對象的業務涵義,同時又減小了實體的數量;在數據建模時,咱們能夠將值對象嵌入實體,減小實體表的數量,簡化數據庫設計。
  3. 值對象的優點和侷限:雙刃劍的存在

    • 優點:簡化數據庫設計,減小實體表的數量,提高數據庫性能
    • 侷限:沒法知足基於值對象的快速查詢,值對象過多時致使堆積缺少完整性的屬性失去業務含義以及操做不方便
  4. 實體與值對象的關係:

    • 最基礎的對象,一塊兒實現實體最基本的核心領域邏輯
    • 引入值對象的重要緣由在於 DDD提倡從領域模型設計出發,而不是先設計數據模型

6. 如何劃分聚合和聚合根

什麼是聚合

  1. 領域模型內的實體和值對象就比如個體,而能讓實體和值對象協同工做的組織就是聚合,它用來確保這些領域對象在實現共同的業務邏輯時,能保證數據的一致性

    • 聚合就是由業務和邏輯緊密關聯的實體和值對象組合而成的,聚合是數據修改和持久化的基本單元,每個聚合對應一個倉儲,實現數據的持久化
  2. 聚合的組成

    1. 聚合根
    2. 上下文邊界:邊界根據業務單一職責高內聚原則,定義聚合內部應該包含哪些實體和值對象,而聚合之間的邊界是鬆耦合。(高內聚、低耦合)
  3. 聚合運用

    1. 屬於DDD分層架構裏的領域層,包含多個聚合,共同實現核心業務邏輯
    2. 聚合內實體以充血模型實現個體業務能力,以及業務邏輯的高內聚
    3. 跨多個實體的業務邏輯經過領域服務來實現
    4. 跨多個聚合的業務邏輯經過應用服務來實現

什麼是聚合根

  1. 目的是爲了不因爲複雜數據模型缺乏統一的業務規則控制,而致使聚合、實體之間數據不一致性的問題
  2. 若是把聚合比做組織,那聚合根就是這個組織的負責人。聚合根也稱爲根實體,它不只是實體,仍是聚合的管理者

    1. 做爲實體自己,擁有實體的屬性和業務行爲,實現自身的業務邏輯
    2. 做爲聚合的管理者,在聚合內部負責協調實體和值對象按照固定的業務規則協同完成共同的業務邏輯
    3. 聚合對外的接口人,以聚合根 ID 關聯的方式接受外部任務和請求,在上下文內實現聚合之間的業務協同

如何設計聚合

DDD 領域建模一般採用事件風暴,它一般採用用例分析、場景分析和用戶旅程分析等方法,經過頭腦風暴列出全部可能的業務行爲和事件,而後找出產生這些行爲的領域對象,並梳理領域對象之間的關係,找出聚合根,找出與聚合根業務緊密關聯的實體和值對象,再將聚合根、實體和值對象組合,構建聚合。
  1. 採用事件風暴,根據業務行爲,梳理出業務過程當中發生這些行爲的全部的實體和值對象
  2. 從衆多的實體中選擇適合做爲對象管理者的根實體(聚合根)。

    1. 判斷一個實體是不是聚合根

      1. 是否有獨立生命週期
      2. 是否有全局惟一ID
      3. 是否能夠建立或修改其餘對象
      4. 是否有專門的模塊來管這個實體
  3. 根據業務單一職責和高內聚原則,找出與聚合根關聯的全部緊密依賴的實體和值對象
  4. 在聚合內根據聚合根、實體和值對象的依賴關係,畫出對象的引用和依賴模型
  5. 多個聚合根據業務語義和上下文一塊兒劃分到同一個限界上下文內

設計原則

  1. 在一致性邊界內建模真正的不變條件。聚合用來封裝真正的不變性,而不是簡單地將對象組合在一塊兒。聚合內有一套不變的業務規則,各實體和值對象按照統一的業務規則運行,實現對象數據的一致性,邊界以外的任何東西都與該聚合無關,這就是聚合能實現業務高內聚的緣由。
  2. 設計小聚合。若是聚合設計得過大,聚合會由於包含過多的實體,致使實體之間的管理過於複雜,高頻操做時會出現併發衝突或者數據庫鎖,最終致使系統可用性變差。而小聚合設計則能夠下降因爲業務過大致使聚合重構的可能性,讓領域模型更能適應業務的變化。
  3. 經過惟一標識引用其它聚合。聚合之間是經過關聯外部聚合根 ID 的方式引用,而不是直接對象引用的方式。外部聚合的對象放在聚合邊界內管理,容易致使聚合的邊界不清晰,也會增長聚合之間的耦合度。
  4. 在邊界以外使用最終一致性。聚合內數據強一致性,而聚合之間數據最終一致性。在一次事務中,最多隻能更改一個聚合的狀態。若是一次業務操做涉及多個聚合狀態的更改,應採用領域事件的方式異步修改相關的聚合,實現聚合之間的解耦(相關內容我會在領域事件部分詳解)。
  5. 經過應用層實現跨聚合的服務調用。爲實現微服務內聚合之間的解耦,以及將來以聚合爲單位的微服務組合和拆分,應避免跨聚合的領域服務調用和跨聚合的數據庫表關聯。
DDD 的一些通用的設計原則,仍是那句話:「適合本身的纔是最好的。」在系統設計過程時,你必定要考慮項目的具體狀況,若是面臨使用的便利性、高性能要求、技術能力缺失和全局事務管理等影響因素,這些原則也並非不能突破的,總之一切以解決實際問題爲出發點。

結語

以上內容爲在學習「極客時間-歐創新老師-DDD實戰課」過程當中記錄下來的筆記,有興趣的同窗能夠買教程細細研究保證有收穫!

相關文章
相關標籤/搜索