本文與大家一起學習並介紹領域驅動設計(Domain Drive Design) 簡稱DDD,以及為什麼我們需要領域驅動設計,它有哪些優缺點,儘量用一些通俗易懂文字來描述講解領域驅動設計,本篇並不會從深層大論述講解落地實現,這些大家可以在瞭解入門後再去深層次學習探討或在後續進階和高階篇瞭解,希望通過本文介紹,可以讓大家快速瞭解DDD並有一個基礎的認知,DDD本身就是理論的集合,很難在不積累理論情況下來有效的實施DDD,僅僅看一些程式碼案例後就開搞,最終出來東西也是東施效顰,莫要好高騖遠。 最後期望大家在工作中能多思考,如你所負責專案如果用DDD如何設計、以及會面臨哪些挑戰。
學習瞭解DDD之前,期望大家可在溫顧下以往我們所瞭解掌握一些知識,努力讓自己所學所掌握的內容沉澱下來,推薦閱讀系列。
領域驅動設計(DDD)提出是從系統的分析到軟體建模的一套方法論。將業務概念和業務規則轉換成軟體系統中的概念和規則,從而降低或隱藏業務複雜性,使系統具有更好的擴充套件性,以應對複雜多變的現實業務問題。總結它是一套完整而系統的設計方法、是一種設計思維、一種方法論,並不是"系統架構",一種架構設計原則、思維。
善於處理高複雜業務的產品研發、可幫助我們提煉穩定的產品核心(領域模型中稱為核心域);
通過建模可提高建模高內聚、降低模型間的耦合度,提高系統的可延伸性與穩定性;
強調團隊與領域專家的合作溝通,有助於建立一個溝通良好的團隊組織;
統一設計思想與設計規範,有助於提高團隊成員的架構設計能力和物件導向設計能力;
現有的微服務建構都是遵循領域驅動設計的架構原則;
如果你負責的軟體系統並不複雜,那麼,你確實不需要學習領域驅動設計!
領域驅動設計的思維是:物件+行為+服務,所有的設計圍圍繞著物件、行為、服務展開;
時下流行架構設計思維是:基於MVC分層架構進行縱向擴充套件,分業務模組進行產品橫向擴充套件;
三層應用架構:資料-應用(業務邏輯層)-展現,通常是以資料位為起點進行資料庫分析設計。
服務層過重,資料模型失血,沒東西;
麵條式程式設計或者面向資料庫程式設計,服務層圍繞資料庫作業完成業務邏輯,經常一條線擼到底;
程式碼一整塊一整塊的過重,很難擴充套件複用;
資料庫模型只是資料庫對映,沒有相關的行為支撐,行為都被上一層Service給完成等了,因此是失血 的領域模型;
架構四層在DDD分層結構中將三層中業務邏輯拆解為應用層和領域層,核心業務邏輯表現下沉到領域層去實現,以業務領域模型為核心建模(物件導向建模),更能體現對現實世界的抽象,其優點如下
沒有誰能夠做到領域驅動設計的一蹴而就,所謂"理論聯絡實際",在剛開始接觸或學習設計領域驅動時,總會有一種訴求希望能給出公式般的設計準則或規範,似乎軟體設計就像拼積木一般,只要遵循圖示給出的拼搭過程,不經思考就能拼出期待的模型,這似乎不切實際的幻想,要掌握領域驅動設計,首先要了解掌握一些概念以知識理論,在此基礎之上思考這些概念背後蘊含的原理,設計原則,思考限界上下文(Bounded Context)邊界的劃分,實際還是圍繞"高內聚、低耦合"原則的體現,只是我們考慮什麼內容才是高內聚,如何抽象才能做到低耦合,在分層架構中,各層之間該如何共同作業?出現了依賴如何解耦,仍然需要從重用與變化的角度去思考設計決策。
領域驅動設計強調以"領域"為核心驅動力,通過模型驅動設計來保障領域模型與程式設計的一致,領域模型不應該包含任何技術實現因素,模型中的物件真實的表達了領域概念,卻不受技術實現的約束,領域模型本身和技術無關,領域驅動從設計上劃分為戰略設計和戰術設計。
強調業務戰略上的重點,如何按重要性分配工作,以及如何進行最佳,遵循量大原則:
必須指導設計決策,以便減少各個部分之間的相互依賴,在使用設計意圖更為清晰的同時而又不失去關鍵的互操作性和系統性;
必須把模型的重點放在捕獲系統概念核心,也就是系統的"遠景"上。
整個業務領域的一部分,關注與宏觀業務,通過對大領域進行劃小在業務間劃分出概念上分界線,便於在系統籌劃階段決策如何分配資源(人、錢)。
關注點在於系統物理劃分,根據你對領域的分割結果及公司或部門的組織結構決策如何劃分子系統,比如分出幾個,系統間如何互動,該層面往往暫不會涉及夠多技術細節。
依賴於領域模型和通用預言,通過技術模式將領域模型和通用預言中的概念對映到程式碼實現中。隨著模型的進化,程式碼實現也會進行重構,以更好的體現模型概念。
代表領域中的概念,如實體、值物件、領域服務、模組等;
用於管理物件的生命週期。如聚合、工廠、倉庫等;
用於整合或跟蹤,如領域事件等;
領域/子域:什麼領域?從廣義上將,領域即是一個組織所做的事情以及所包含的一切,領域可大可小有界限,不是無限大,如電商領域,交易領域,購物領域等,比如我們常聽客戶說「我們有這樣幾塊業務」一般來說這裡所謂"幾塊兒"就是指子域 。
實體(entity):這個詞被我們廣泛使用,甚至過分使用,實體是一個重要的概念,一個典型實體應具備3個要素(身份標識、屬性、領域行為),必須有唯一的身份標識,沒有身份標識的領域物件就不是實體。如:User物件就是一個實體。
屬性:實體的屬性用來說明主體的靜態特徵,並持有資料與狀態。
@Data
public class Product{
private String sku;
private String name;
private Price price;
}
@Data
public class Product{
private String sku;
private String name;
private Price price;
//變更狀態的領域行為
public void changePriceTo(Price newPrice){
//設計產品新加個
.......
}
}
舉個小例子:訂單項和訂單的關係:多對一,一個訂單裡有多條訂單項,一個訂單項,只會出現在一個訂單裡,組合關係,部分不能脫離主體單獨存在
public class Order {
int id;
User user;
}
public class OrderItem {
private int id;
private Product product;
private int num;
private Order order;
}
6) 聚合根:聚合中需要指定一個實體作為聚合根來作為整個聚合的對外觸電,也就是說外部只能通過聚合根實現對內部物件的存取,這樣的限制可以對內部物件實現最大化的保護。
幾乎所有專案的發展都有這樣一個規律:初期需求簡單,中後期業務激增系統複雜度升級,導致最初的設計理念需要大刀闊斧的改革,所以,系統越複雜、程式碼規模越大,DDD 的優勢就越明顯。
微服務劃分的一個重要理論基礎就是領域驅動設計,但由於DDD門檻高、概念多,體系龐大又抽象,再加上實踐經驗和案例缺少,很多開發人員對DDD存在不少疑惑,或只停留在平時依靠檢索或身邊同事談及耳聞了解DDD,通過本篇初步認識了領域驅動設計、前期我們先暫短介紹這裡,後續會將從程式碼層面入手分享DDD實現落地。
作者:京東物流 邊雷
來源:京東雲開發者社群 自猿其說Tech 轉載請註明來源