領域驅動設計理解&總結 這篇文章主要是通讀《實現領域驅動設計》以後本身的理解和總結(同時也參照一些博文的分析來加深本身的理解);html
有些疑問是自定義內容,雖然有本身的理解,但依然感受較爲抽象,後續會經過實踐來理解其中的精妙之處。數據庫
領域驅動設計 做爲一種軟件開發方法,提供了戰略上(思考方式) 和 戰術上(落地方式) 的建模工具來幫助咱們 設計高質量的軟件模型;架構
領域驅動設計 不是關於技術的,而是關於討論、聆聽、理解、發現業務價值 的,目的是將 知識 集中起來,造成 通用語言(Ubiquitous Language);框架
在 領域驅動設計 中,技術也重要,但更重要的是要掌握 領域建模 中更高層次的概念;工具
在領域中構建模型,什麼是 領域模型?ui
關於 某個特定業務領域的軟件模型。一般,領域模型經過 對象模型 來實現,這些對象包含了數據和行爲,而且表達了準確的業務含義。spa
Vaughn Vernon(沃恩.弗農) 在他的書裏(《實現領域驅動設計》)闡述了不少,總結3點:架構設計
領域專家、開發者、業務人員等都掌握一樣的軟件知識,你們都使用相同的語言進行交流,每一個人互相理解彼此在說什麼;翻譯
設計就是代碼,代碼就是設計,軟件可以表達你們所理解的意思;設計
DDD持續關注業務,會產生一些業務價值
得到一個有用的 領域模型;
業務獲得更準確的 定義和理解;
領域專家能夠爲領域設計作出貢獻;
更好的用戶體驗(軟件自己容易上手,減小培訓,提升效率)
清晰的模型邊界
良好的企業架構
敏捷、迭代式和持續建模
使用 戰略和戰術工具
建立通用語言(全部人達成一致的某個業務術語的統一認知)消耗額外的時間和精力
持續的將領域專家引入項目
改變開發者 對領域的思考方式
DDD 提供了戰略上 和 戰術上 的建模工具來幫助咱們 設計高質量的軟件模型,戰略設計 側重於高層次、宏觀上去劃分和集成限界上下文,而 戰術設計 則關注更具體使用建模工具來細化上下文。
限界上下文(Bounded Context) 爲團隊建立一個建模邊界;
成員在邊界內部爲特定的 業務領域 建立 解決方案;
單個限界上下文中團隊成員共享一套 通用語言(Ubiquitous Language);
不一樣團隊各自負責一個限界上下文,可使用 上下文映射圖 對限界上下文進行 界分和集成;
實體(Entity)
值對象(Value Object)
聚合(Aggregate)
領域服務(Domain Service)
領域事件(Domain Event)
資源庫(Repository)
下邊我針對 戰略和戰術 兩個方面進行講解
廣義上講:領域 是一個組織所作的事情以及其中所包含的一切(爲某個組織開發軟件時,你面對的就是這個組織的 領域)。
軟件開發中:領域 既能夠表示 整個業務系統,也能夠表示系統中的 核心域 或者 支撐子域。
在DDD中:領域 被劃分爲若干 子域,領域模型 在 限界上下文 中完成開發。
領域 包括下邊三種 子域:
核心域(業務成功的主要促成因素,是企業的核心競爭力,應該給予最高的優先級、最資深的領域專家和最優秀的開發團隊,實施DDD的過程當中主要關注於 核心域);
支撐子域(不是核心,對應業務的 某些重要方面,有時咱們會建立或者購買某個支撐子域);
通用子域(不是核心,但被整個業務系統所使用);
現實世界中的領域包括 問題空間(Problem Space)和 解決方案空間(Solution Space):
問題空間:是核心域和其餘子域的組合,思考的是 業務面臨的挑戰
解決方案空間:一組特定的 軟件模型,包括一個或多個限界上下文,思考的是如何實現軟件(限界上下文 便是一個 特定的解決方案,經過軟件的方式實現解決方案)以 解決這些業務挑戰
一個 顯式的邊界(主要是一個語義上的邊界),領域模型便存在於這個邊界以內;每個模型概念(包括它的屬性和操做)在邊界以內都具備特殊的含義;
一個 給定的業務領域 會包含多個限界上下文,想與一個限界上下文溝通,則須要經過顯示邊界進行通訊;系統經過肯定的限界上下文來進行解耦,而每個上下文內部緊密組織,職責明確,具備較高的內聚性;
一個很形象的隱喻:細胞質因此可以存在,是由於細胞膜限定了什麼在細胞內,什麼在細胞外,而且肯定了什麼物質能夠經過細胞膜(引用);
將限界上下文想象成技術組件是能夠的,可是技術組件並 不能來定義(是說不能定義概念?) 限界上下文,有幾種作法:
在使用 IntelliJ IDEA 時,一個 限界上下文 一般就是一個工程項目;
在使用Java時,頂層包名一般表示 限界上下文中頂層模塊 的名字;
一個團隊,一個限界上下文(即使項目按分層架構模塊劃分,團隊依然應該只工做在一個限界上下文中);
肯定了單個限界上下文以後,有時還須要肯定多個限界上下文之間的關係,這時就須要上下文映射圖
一個項目的 上下文映射圖 能夠用兩種方式來表示:
畫一個簡單的框圖來表示 兩個或多個 限界上下文 之間的 映射關係(該框圖表示了不一樣的限界上下文在 解決方案空間 中是如何經過集成相互關聯的);
經過 限界上下文 集成的源代碼實現來表示;
康威定律 告訴咱們,系統結構 應儘可能與 組織結構 保持一致
這裏認爲團隊結構(不管是內部組織仍是團隊間組織)就是 組織結構,限界上下文 就是 系統結構;
所以,團隊結構 應該和 限界上下文 保持一致。
梳理清楚上下文之間的關係,從 團隊內部 的關係來看,有以下好處:
任務更好拆分(一個開發人員能夠全身心的投入到相關的一個單獨的上下文中);
溝通更加順暢(一個上下文能夠明確本身對其餘上下文的依賴關係,從而使得團隊內開發直接更好的對接);
從 團隊間 的關係來看,明確的上下文關係可以帶來以下幫助:
每一個團隊在它的限界上下文中可以更加明確本身領域內的概念(由於限界上下文是領域的 解決方案空間);
對於限界上下文之間發生交互,團隊與限界上下文的一致性,可以保證咱們明確對接的團隊和依賴的上下游;
合做關係(Partnership):兩個限界上下文創建起來的一種 緊密合做關係,要麼一塊兒成功,要麼一塊兒失敗;
共享內核(Shared Kernel):兩個限界上下文緊密依賴共享的 部分模型和代碼;
客戶方-供應方開發(Customer-Supplier Development):兩個限界上下文有計劃的 產生相互依賴(當兩個團隊處於上下游關係時,下游團隊開發會受到上游開發的影響,上游團隊計劃應該估計下游團隊的需求);
遵奉者(Conformist):下游限界上下文只能 盲目依賴 上游限界上下文的現象;
防腐層(Anticorruption Layer):一個限界上下文經過轉換和翻譯與其餘的限界上下文進行交互;
開放主機服務(Open Host Service):定義一種協議,讓其餘限界上下文經過該協議對本限界上下文進行訪問;
發佈語言(Published Language):兩個限界上下文之間翻譯模型所須要的公用語言,一般與開放主機服務一塊兒使用;
另謀他路(Separate Way):兩個限界上下文之間不存在任何關係,尋找另外更簡單、更專業的方法來解決問題;
大泥球(Big Ball of Mud):混雜在一塊兒的、邊界很是模糊的限界上下文關係;
在劃分的過程當中,常常糾結的一個問題是:這個模型(概念或數據)看起來放這個領域合適,放另外一個也合適,如何抉擇 呢?
依據該模型與邊界內其餘模型或角色 關係的緊密程度(好比,是否當該模型變化時,其餘模型也須要進行變化;該數據是否一般由當前上下文中的角色在當前活動範圍內使用);
服務邊界內的 業務能力職責應單一,不是完成同一業務能力的模型不放在同一個上下文中;
劃分的子域和服務需知足 正交原則(模塊的獨立性,領域名字表明的天然語言上下文保持互相獨立);
組織中 業務部分的劃分 也是一種參考(組織架構,一個業務部門的存在每每有其獨特的業務價值);
簡單打個比方,同一個領域上下文中的模型要保持 近親關係,五福之內,同一血統(業務)。
當一個對象由其 惟一的身份標誌 區分、具備可變的特性,這種對象即爲實體。
實體屬性的驗證能夠放在實體內部進行
將領域概念建模成 值對象 的時候,應該將通用語言考慮在內,這是前提。(爲何將通用語言考慮在內?值對象 是領域裏的一個概念,你們要統一認知,用通用語言做爲標準,能夠達到共同理解的目的)
構建值對象,要了解 值對象 如下的特色:
它度量或者描述了 領域中的一件東西;
它能夠做爲 不變量;
它將不一樣的相關的屬性組合成一個 概念總體;
當度量和概念改變時,能夠用另外一個值對象予以 替換;
它能夠和其餘值對象進行相等性 比較;
它不會對協做對象形成任何反作用;
在實踐中,須要保證值對象建立後就不能被修改,即不容許外部再修改其屬性(如:在訂單上下文中若是你只關注下單時商品信息快照,那麼將商品對象視爲值對象是很好的選擇)
聚合(Aggregate)是一組相關對象的集合,做爲一個總體被外界訪問,它由 實體 和 值對象 在 一致性邊界以內 組成,聚合根(Aggregate Root)是這個聚合的根節點。
在設計聚合時,咱們須要慎重的考慮 一致性
關注聚合的 一致性邊界,在一致性邊界以內建模真正的 不變條件(不變條件 指的是業務規則)
同一個事務以內不能修改多個 聚合實例
在邊界以外使用 最終一致性
設計 小聚合;(「小」 的極端意思是指 一個聚合只擁有全局標識和單個屬性;這種作法不推薦)
經過惟一標識來引用其餘聚合或實體:當存在對象之間的關聯時,建議引用其惟一標識而非引用其總體對象(若是是外部上下文中的實體,引用其惟一標識或將須要的屬性構造值對象)
注:若是聚合建立複雜,推薦使用 工廠方法 來屏蔽內部複雜的建立邏輯
當領域中的某個操做過程或轉換過程不是實體或者值對象的職責時,將該操做放在一個單獨的接口中,即 領域服務。
領域服務 和通用語言一致,表示 無狀態 的操做,它用於實現特定於某個領域的任務;
某個操做不適合放在實體(聚合)與值對象上時,適合 領域服務;
執行一個顯著的業務操做過程;
對領域對象進行轉換;
以多個領域對象做爲輸入進行計算,結果產生一個值對象;
領域服務 是用來處理業務邏輯的(咱們不能將業務邏輯放到應用層,即便很是簡單,它依然是業務邏輯)
對 領域中 所發生的事件(領域專家所關心的發生在領域中的一些事件)進行建模,即 領域事件(領域模型 的組成部分)
領域事件 用來捕獲領域中發生的一些事情,開始使用領域事件時,要 對不一樣的事件進行定義;
「當...時,請通知我」 等等場景
限界上下文內,觀察者模式 是一種簡單高效的發佈領域事件的方法;
限界上下文外,利用 消息機制 將本地限界上下文產生的事件發送到 遠程限界上下文 中(咱們要保證 全部限界上下文 的最終一致性);
對領域的存儲和訪問進行統一管理的對象,即 資源庫(Repository);
一般咱們將 聚合實例 存放在資源庫中,以後再經過資源庫獲取相同的實例;
一般來講,聚合類型 和 資源庫之間存在着 一對一的關係;
當兩個或多個聚合位於同一個對象層級中時,他們能夠共享同一個資源庫;
注:資源庫和 DAO是不一樣的,一個DAO主要從數據庫表的角度來看待問題,而且提供 CRUD 操做
極簡化架構設計主要從下邊三個角度出發:
業務架構:根據業務需求設計業務模塊及交互關係;
系統架構:根據業務需求設計系統和子系統的模塊;
技術架構:根據業務需求決定採用的技術及框架;
DDD的核心訴求 就是可以讓 業務架構 和 系統架構 造成綁定關係,從而當咱們去響應 業務變化 調整業務架構時,系統架構的改變是隨之自發的
這個 業務變化 的結果有兩個:
業務架構 的梳理和 系統架構 的梳理是同步漸進的,其結果是劃分出的 業務上下文 和 系統模塊結構 是綁定的;
技術架構 是解耦的,能夠根據劃分出來的業務上下文的系統架構選擇最合適的實現技術;
全部架構的始祖,支持N層架構系統,將一個應用程序或者系統分爲不一樣的層次
DDD使用的傳統分層架構:
分層架構原則:每層只能與其下方的層發生耦合(分層架構 分爲 嚴格分層架構 和 鬆散分層架構)。
嚴格分層架構:每層只能和直接位於其下方的層發生耦合。
鬆散分層架構:任意上方層與任意下方層發生耦合。
六邊形結構(端口與適配器架構、onion架構):一種具備對稱性特徵的架構風格。
爲何是6邊形?不是4邊形或8邊形?
六邊形架構視角:架構中存在兩個區域,「外部區域」和「內部區域」,外部區域 供給客戶提交輸入,內部區域 獲取持久化數據、對數據進行存儲或轉發。
服務設計原則
服務契約:經過契約文檔,服務闡述自身的目的與功能;
鬆耦合:服務將依賴關係最小化;
服務抽象:服務只發布契約,隱藏內部邏輯;
服務重用性:一種服務可被其餘全部服務重用;
服務自治性:服務自行控制環境與資源以保持獨立性;
服務無狀態性:服務負責消費方的狀態管理;
服務可發現性:客戶可經過服務元數據來查找服務和理解服務;
服務組合性:一種服務可用由其餘服務組合而成,不用管其餘服務的大小和複雜性如何;
原文出處:https://www.cnblogs.com/zhangxiaoguang/p/ddd.html