1 前言
本文與大家一起學習并介紹領域驅動設計(Domain Drive Design) 簡稱DDD,以及為什么我們需要領域驅動設計,它有哪些優(yōu)缺點,盡量用一些通俗易懂文字來描述講解領域驅動設計,本篇并不會從深層大論述講解落地實現(xiàn),這些大家可以在了解入門后再去深層次學習探討或在后續(xù)進階和高級篇了解,希望通過本文介紹,可以讓大家快速了解DDD并有一個基礎的認知,DDD本身就是理論的集合,很難在不積累理論情況下來有效的實施DDD,僅僅看一些代碼案例后就開搞,最終出來東西也是東施效顰,莫要好高騖遠。 最后期望大家在工作中能多思考,如你所負責項目如果用DDD如何設計、以及會面臨哪些挑戰(zhàn)。
學習了解DDD之前,期望大家可在溫顧下以往我們所了解掌握一些知識,努力讓自己所學所掌握的內容沉淀下來,推薦閱讀系列。
- Head First 設計模式:基礎面向對象概念和重要的設計模式;
- UML面向對象建?;A:從需求到分析,從分析到設計,從設計到編碼,UML都有用武之地
- 實現(xiàn)領域驅動設計:很厚,更加務實,推薦閱讀
- 領域驅動設計:張逸-DDD開山之作,挺玄幻的,多讀幾遍受益匪淺;
2 定義與概念
領域驅動設計(DDD)提出是從系統(tǒng)的分析到軟件建模的一套方法論。將業(yè)務概念和業(yè)務規(guī)則轉換成軟件系統(tǒng)中的概念和規(guī)則,從而降低或隱藏業(yè)務復雜性,使系統(tǒng)具有更好的擴展性,以應對復雜多變的現(xiàn)實業(yè)務問題。總結它是一套完整而系統(tǒng)的設計方法、是一種設計思維、一種方法論,并不是"系統(tǒng)架構",一種架構設計原則、思維。
2.1、為什么要使用"領域驅動設計",或者說其用途,應用場景式什么?
-
善于處理高復雜業(yè)務的產品研發(fā)、可幫助我們提煉穩(wěn)定的產品內核(領域模型中稱為核心域);
-
通過建??商岣呓8邇染邸⒔档湍P烷g的耦合度,提高系統(tǒng)的可擴展性與穩(wěn)定性;
-
強調團隊與領域專家的合作溝通,有助于建立一個溝通良好的團隊組織;
-
統(tǒng)一設計思想與設計規(guī)范,有助于提高團隊成員的架構設計能力和面向對象設計能力;
-
現(xiàn)有的微服務建構都是遵循領域驅動設計的架構原則;
-
如果你負責的軟件系統(tǒng)并不復雜,那么,你確實不需要學習領域驅動設計!
2.2、領域驅動設計跟時下流行的架構思維最大的區(qū)別是什么?
領域驅動設計的思維是:對象+行為+服務,所有的設計圍圍繞著對象、行為、服務展開;
時下流行架構設計思維是:基于MVC分層架構進行縱向擴展,分業(yè)務模塊進行產品橫向擴展;
2.2.1. 傳統(tǒng)的方案
三層應用架構:數(shù)據-應用(業(yè)務邏輯層)-展現(xiàn),通常是以數(shù)據位為起點進行數(shù)據庫分析設計。
-
服務層過重,數(shù)據模型失血,沒東西;
-
面條式編程或者面向數(shù)據庫編程,服務層圍繞數(shù)據庫作業(yè)完成業(yè)務邏輯,經常一條線擼到底;
3)? 代碼一整塊一整塊的過重,很難擴展復用;
- 數(shù)據庫模型只是數(shù)據庫映射,沒有相關的行為支撐,行為都被上一層Service給完成等了,因此是失血 的領域模型;
2.2.2. 領域驅動方案
架構四層在DDD分層結構中將三層中業(yè)務邏輯拆解為應用層和領域層,核心業(yè)務邏輯表現(xiàn)下沉到領域層去實現(xiàn),以業(yè)務領域模型為核心建模(面向對象建模),更能體現(xiàn)對現(xiàn)實世界的抽象,其優(yōu)點如下
1)? 輕服務層+充血的領域模型;
-
領域模型封裝和實現(xiàn)各自應有的行為,可以認為是一個高內聚、低耦合的組件;
-
由于模型集數(shù)據與行為于一身,是一種自解釋的對象,代碼復用性高,業(yè)務邏輯清晰明確;
- 用戶界面層:主要職責是通過用戶界面向用戶顯示數(shù)據信息,同時解釋用戶的命令,并把用戶的請求發(fā)送到應用層。
- 應用層:通過調用基礎設置和領域層完成數(shù)據資源操作及業(yè)務流程編排,相當于BS層;
- 領域層:將業(yè)務邏輯高度內聚到領域層,所以領域層是整個系統(tǒng)的核心,它只與實際業(yè)務相關,不關心任何技術細節(jié),盡可能做到與持久化無關;
- 基礎設施層:包含了任何類型的框架、數(shù)據庫訪問代碼或者公共的方法等,純技術的一層;
2.3、如何學習領域驅動設計
沒有誰能夠做到領域驅動設計的一蹴而就,所謂"理論聯(lián)系實際",在剛開始接觸或學習設計領域驅動時,總會有一種訴求希望能給出公式般的設計準則或規(guī)范,似乎軟件設計就像拼積木一般,只要遵循圖示給出的拼搭過程,不經思考就能拼出期待的模型,這似乎不切實際的幻想,要掌握領域驅動設計,首先要了解掌握一些概念以知識理論,在此基礎之上思考這些概念背后蘊含的原理,設計原則,思考限界上下文(Bounded Context)邊界的劃分,實際還是圍繞"高內聚、低耦合"原則的體現(xiàn),只是我們考慮什么內容才是高內聚,如何抽象才能做到低耦合,在分層架構中,各層之間該如何協(xié)作?出現(xiàn)了依賴如何解耦,仍然需要從重用與變化的角度去思考設計決策。
3 領域驅動設計
領域驅動設計強調以"領域"為核心驅動力,通過模型驅動設計來保障領域模型與程序設計的一致,領域模型不應該包含任何技術實現(xiàn)因素,模型中的對象真實的表達了領域概念,卻不受技術實現(xiàn)的約束,領域模型本身和技術無關,領域驅動從設計上劃分為戰(zhàn)略設計和戰(zhàn)術設計。
- 一個領域是由一個或多個模型組成;
- 從定義上講模型是領域的抽象;
- 從理解上將模型可以認為是一個高內聚、低耦合的組件、模塊,也可以稱為一個子領域;
- 模型重在建模過程,建模過程會抽象出一系列領域對象和領域服務;
- 在DDD中,定義一系列的標準"領域元素"用于領域建模;如戰(zhàn)術設計元模型
3.1. 戰(zhàn)略設計
強調業(yè)務戰(zhàn)略上的重點,如何按重要性分配工作,以及如何進行最佳,遵循量大原則:
-
必須指導設計決策,以便減少各個部分之間的相互依賴,在使用設計意圖更為清晰的同時而又不失去關鍵的互操作性和系統(tǒng)性;
-
必須把模型的重點放在捕獲系統(tǒng)概念核心,也就是系統(tǒng)的"遠景"上。
3.1.1 子域劃分
整個業(yè)務領域的一部分,關注與宏觀業(yè)務,通過對大領域進行劃小在業(yè)務間劃分出概念上分界線,便于在系統(tǒng)籌劃階段決策如何分配資源(人、錢)。
1)? 核心子域:領域中最有價值和最核心的部分,產品成敗的關鍵,核心競爭力,在DDD開發(fā)中,主要關注核 心域,給予最高優(yōu)先級;
-
支撐子域:項目中對核心子域起著支撐作用的相關功能,專注于業(yè)務的某個反面;
-
通用子域:與項目意圖無關的內聚子領域,解決一些通用問題,任何專有的業(yè)務都不應該放在通用子域;
3.1.2. 戰(zhàn)略建模
關注點在于系統(tǒng)物理劃分,根據你對領域的分割結果及公司或部門的組織結構決策如何劃分子系統(tǒng),比如分出幾個,系統(tǒng)間如何交互,該層面往往暫不會涉及夠多技術細節(jié)。
1)? 限界上下文(Bounded Context):通俗講指系統(tǒng)中模塊,微服務架構中的子服務、單體中"包(Java)"或名稱空間(C#),對系統(tǒng)的一個物理劃分,限定了領域模型的邊界,在更深層次介紹深挖,這東西得分成兩個詞:限界、上下文,可以理解成系統(tǒng)設計之初,你需要畫一個圈設置一個范圍,保證領域模型限制在這個圈內不可串場,這個‘圈’即為限界上下文。
-
通用語言:用于統(tǒng)一領域專家、產品、研發(fā)、測試大家在使用的語言,避免出現(xiàn)需求理解不一致,設計與需求不一致,溝通不順暢等問題,簡單來說大家在一起聊某個東西的時候都能明白彼此所致的是什么,場景不同,同一個詞就會有著不同含義。
-
上下文映射圖:用圖的方式,表達出限界上下文之間關聯(lián),后續(xù)會單獨在詳細介紹上下文映射圖,如 合作關系、防腐層、大泥球等;
3.2. 戰(zhàn)術設計
依賴于領域模型和通用預言,通過技術模式將領域模型和通用預言中的概念映射到代碼實現(xiàn)中。隨著模型的進化,代碼實現(xiàn)也會進行重構,以更好的體現(xiàn)模型概念。
- 主要包括:
-
代表領域中的概念,如實體、值對象、領域服務、模塊等;
-
用于管理對象的生命周期。如聚合、工廠、倉庫等;
-
用于集成或跟蹤,如領域事件等;
3.3. 名詞解釋
-
領域/子域:什么領域?從廣義上將,領域即是一個組織所做的事情以及所包含的一切,領域可大可小有界限,不是無限大,如電商領域,交易領域,購物領域等,比如我們常聽客戶說“我們有這樣幾塊業(yè)務”一般來說這里所謂"幾塊兒"就是指子域 。
-
實體(entity):這個詞被我們廣泛使用,甚至過分使用,實體是一個重要的概念,一個典型實體應具備3個要素(身份標識、屬性、領域行為),必須有唯一的身份標識,沒有身份標識的領域對象就不是實體。如:User對象就是一個實體。
-
屬性:實體的屬性用來說明主體的靜態(tài)特征,并持有數(shù)據與狀態(tài)。
@Data
public class Product{
private String sku;
private String name;
private Price price;
}
- 領域行為:實體擁有領域行為,可以更好地說明其作為主體的動態(tài)特征。一個不具備動態(tài)特征的對象不屬于領域行為。
@Data
public class Product{
private String sku;
private String name;
private Price price;
//變更狀態(tài)的領域行為
public void changePriceTo(Price newPrice){
//設計產品新加個
.......
}
}
- 值對象(value object):比較抽象,通常作為實體的屬性,區(qū)分值對象與實體的區(qū)別在于,值對象是不可變的,并且沒有唯一標識,僅由其屬性的值定義,參與則對它的判斷是依據值還是依據身份標識,前者是值對象,后者是實體;
舉個小例子:訂單項和訂單的關系:多對一,一個訂單里有多條訂單項,一個訂單項,只會出現(xiàn)在一個訂單里,組合關系,部分不能脫離主體單獨存在
public class Order {
int id;
User user;
}
public class OrderItem {
private int id;
private Product product;
private int num;
private Order order;
}
6)? 聚合根:聚合中需要指定一個實體作為聚合根來作為整個聚合的對外觸電,也就是說外部只能通過聚合根實現(xiàn)對內部對象的訪問,這樣的限制可以對內部對象實現(xiàn)最大化的保護。
4 價值是什么
幾乎所有項目的發(fā)展都有這樣一個規(guī)律:初期需求簡單,中后期業(yè)務激增系統(tǒng)復雜度升級,導致最初的設計理念需要大刀闊斧的改革,所以,系統(tǒng)越復雜、代碼規(guī)模越大,DDD 的優(yōu)勢就越明顯。
- 合作溝通:強調團隊與領域專家的合作溝通,有助于建立一個溝通良好的團隊組織;
- 統(tǒng)一思想:統(tǒng)一設計思想與設計規(guī)范,有助于提高團隊成員的架構設計能力和面向對象設計能力;
- 系統(tǒng)靈活:通過建模可提高模型的高內聚,降低模型建的耦合度,提高系統(tǒng)的可擴展性與穩(wěn)定性;
- 產品內核:善于處理高復雜度業(yè)務產品研發(fā),可幫助我們提煉穩(wěn)定的產品內核;
- 業(yè)務沉淀:領域模型是系統(tǒng)的核心,是領域內業(yè)務的直接沉淀,具有非常大的業(yè)務價值。
5 基礎篇結束語
微服務劃分的一個重要理論基礎就是領域驅動設計,但由于DDD門檻高、概念多,體系龐大又抽象,再加上實踐經驗和案例缺少,很多開發(fā)人員對DDD存在不少疑惑,或只停留在平時依靠檢索或身邊同事談及耳聞了解DDD,通過本篇初步認識了領域驅動設計、前期我們先暫短介紹這里,后續(xù)會將從代碼層面入手分享DDD實現(xiàn)落地。
作者:京東物流 邊雷文章來源:http://www.zghlxwxcb.cn/news/detail-704213.html
來源:京東云開發(fā)者社區(qū) 自猿其說Tech 轉載請注明來源文章來源地址http://www.zghlxwxcb.cn/news/detail-704213.html
到了這里,關于快速理解DDD領域驅動設計架構思想-基礎篇 | 京東物流技術團隊的文章就介紹完了。如果您還想了解更多內容,請在右上角搜索TOY模板網以前的文章或繼續(xù)瀏覽下面的相關文章,希望大家以后多多支持TOY模板網!