DDD領域驅動設計:業務分析神奇
1. DDD設計篇:運用事件風暴法進行業務領域建模、統一語言建模
1.1 如何成為優秀架構師?
架構師 = 技術大牛?
架構師不僅需要懂技術,還要懂業務。
只有將業務落地到技術,開發出對使用者有價值的產品,技術才是有價值的。
什麼是業務架構師?
掌握了業務領域知識,掌握了業務痛點,然後用技術方案,解決業務痛點,才能為公司創造價值。
架構師
-
要能夠將業務轉換為技術
-
能合理運用技術支撐業務
客戶買單,不是買技術,而是買你用技術解決我業務痛點的技術方案。
所以上面一步步分析後,業務痛點是關鍵
1.2.1 對業務及其痛點,有深刻的理解與思考
不僅要理解業務,還要挖掘出業務痛點,才才可以用對應的技術來解決問題
-
分析業務流程
-
理解業務規則
-
挖掘業務痛點
1.2.2 能夠將技術落地,產生業務價值
- 規劃高遠卻落不了地
- 快速研發產生業務價值
關鍵難題:
- 如何快速有效地學習業務領域知識
- 如何深入地理解與挖掘業務痛點
- 如何通過技術的手段落地業務
系統沒那麼複雜時,需要領域驅動嗎?
系統不復雜時,領域驅動有點大材小用,以前網際網路時代沒到來,沒有發生資料和需求井噴,業務也不復雜,所以不會流行起來。
現在基本都需要,特別是網際網路業務。
1.2 領域驅動設計在什麼時候起作用?
1.2.1 在新專案開發中起作用?
-
深刻理解業務,進行領域建模
-
然後把業務轉換為領域模型,
-
再用領域模型指導資料庫設計和程式設計
-
按照貧血模型或者充血模型轉換為程式設計
這個時候,一開始需要花大量時間進行領域建模。
但是新專案有一些特點
1、複雜度沒那麼高
2、要快速交付
怎麼辦?一開始沒辦法,用領域驅動,是考慮長遠,在日後,專案需求變更、維護。
1.2.2 在老專案維護中起作用?
面對老專案越來越複雜時,領域驅動會更好的發揮作用
快速交付?
通過領域驅動設計,提高維護的質量,使得可以在業務不斷迭代、市場激烈競爭、技術快速更新、系統越來越龐大時,依然能快速交付高質量的產品。
我們採用整潔架構,將業務程式碼和技術框架,通過一箇中間層進行解耦。
今後,我們的業務程式碼隨著業務不斷迭代,技術框架也可以不斷迭代調整,互不影響。
1.2.3 在技術架構演化中起作用?
1.3 領域驅動的解決之道
首先,業務負責人(或產品經理),以故事的形式,將功能分發給多個敏捷團隊,每個敏捷團隊負責一個功能模組。
每個敏捷團隊,在開發的過程中,結合領域驅動設計和微服務架構理念,設計功能。
我們按照業務去拆
微服務如何拆分?
介面怎麼劃定?
怎麼將每次的需求只落到一個微服務裡?
讓每個微服務,都是軟體變化的一個原因,
今後因為這個原因而發生的變更,都只發生在這個微服務。微服務的優勢才真正發揮出來了。
每次需求變更時,基於領域驅動設計,進行業務建模,
最後把對業務建模的變更,落實到對微服務的變更
我們的系統才能高質量的低成本維護下去。
在我們結合領域驅動設計和微服務架構理念去做設計時,都是有一定的成本的,從而提高了系統設計的複雜度。
複雜度的增加,進一步降低了交付速度。又和我們的初衷產生矛盾。
我們的初衷,通過領域驅動設計和微服務,簡化設計,降低維護成本,提高交付速度
而使用它們的成本,又會降低交付速度
這個矛盾怎麼解決?
架構團隊,架構一個支援微服務,支援領域驅動的架構,把我們在領域驅動中的一些複雜的設計,比如聚合、倉庫、工廠下沉,落地到技術框架裡,
一邊基於業務領域模型,建立業務領域層,
一邊將各個技術框架,通過介面卡進行解耦。
這就是整潔架構。
1.3.1 為什麼需要領域驅動設計指導微服務的劃分?
首先看下,傳統的煙囪式的資料庫設計
這樣的資料庫設計,使用的時候,比如獲取商品資訊這個資料的時候,各個微服務都要去讀取商品表,
一旦商品表發生變更,各個模組都要變更程式碼。
這樣維護成本非常高。
怎麼辦?
那我們希望某一次變更,只需要改某個微服務的程式碼,縮小需求變更的影響範圍
1.3.2小而專的微服務設計
小:拆分微服務
專:單一職責原則(容易被忽略)
怎麼做?
要求每個表只能有一個微服務直接操作資料庫,其他微服務想要操作是不行的,只能呼叫對應微服務的介面。
這樣設計後,商品表變更,只會影響到商品維護這個微服務。
只要對外介面不變,其他微服務也不需要改程式碼,影響很小
對資料表進行規劃,哪個微服務操作哪些表。
提高內聚,從業務角度分析整理,劃分清楚邊界。
業界現在最有效的做這個事情的方法,就是領域驅動設計,
通過對業務的梳理,逐步建立起限界上下文。
然後基於限界上下文設計和開發系統
1.3.3 跨庫關聯查詢解決方案
方案:按照領域模型建模,建立好關聯關係,底層架構自動幫我補填資料。
比如我下單,我只關心查訂單資料,我建立領域模型時,建立了訂單和其他模組的業務關係,配置好業務關係,底層架構自動幫我補填資料。
1.4 本課程要解決的問題
領域驅動設計的作用與意義
真正的目的不在於開發新專案,新專案沒有那麼複雜,而在於,日後的維護,系統越來越複雜時,體現出來。
一開始用領域驅動的意義,在於,日後的維護,系統複雜的時候,提高程式碼質量,降低交付時間。
怎樣正確地進行業務領域建模
今天的內容
事件風暴
需求變更
為什麼越來越複雜?
這是軟體發展的必然規律
傳統的設計方式,隨著新需求的到來,不斷地往payoff()方法裡塞程式碼。
這樣會導致程式碼質量不斷下降,維護成本不斷提高。
軟體退化的根源,不是需求變更
當我們需求變更的時候,我們適時地調整程式碼。進行解耦和功能擴充套件,再去實現需求,就能夠實現高質量程式碼
那麼我們怎樣適時調整程式碼,解耦和擴充套件呢?
當發生10次、50次、100次變更後,可能就迷失方向了
我們需要一個方法,無論多少次變更,都能夠產生高質量程式碼
當我們需求變更時,把變更還原到真實世界裡,真實世界是什麼樣子,我們軟體就怎麼變更。
這樣,無論發生多少次變更,我們也能找到方向。
在領域模型裡變更,思考設計
面對變更,傳統設計方式如下圖,直接塞程式碼。
而領域驅動的設計方式,我們先將新需求,還原到領域模型上,進行分析
我們要增加折扣,而且有多種不同方式的折扣。
我們需要思考,付款和折扣有什麼關係?
折扣的功能,怎麼新增到現有功能裡?
傳統思考方式:折扣是在付款的時候折扣,就寫在付款的邏輯裡
那麼難道不寫在付款裡?為什麼不該寫在付款裡?是基於什麼原則去思考的嗎?
有,單一職責原則
抽象出限界上下文,每個限界上下文就是一個微服務
每個微服務是軟體變化的一個原因,有需求變更,只需要改某個微服務
怎樣將模型轉換為程式設計
明天分享
支援領域驅動設計的架構設計
第三天的分享內容
1.5 單一職責原則(SRP)
軟體系統中的每個元素只完成自己職責內的事,將其他的事交給別人去做。
“職責”通常理解為一個事情,與該事情相關的事都是它的職責。
一個所謂職責,其實是軟體變化的一個原因。
軟體質量如何衡量?高還是低?
關鍵:維護成本
一個需求來了,我要改3個模組的程式碼
一個需求來了,我要改1個模組的程式碼
要求我們
平時,就要整理程式碼。
把同一個原因的程式碼放一起。
不同原因的程式碼分開放
現在要增加折扣,問自己兩個問題:
付款變了,要不要變折扣?不要
折扣發生變更,付款要不要變?要
折扣是付款的另一個變化原因,不應該把折扣放進付款裡
1.6 領域驅動設計與傳統軟體開發有什麼不同?
專案不變更,不需要新增新功能,不會越來越複雜,就不需要使用DDD
新專案裡用領域驅動設計,是為了日後需求變更,維護起來更容易。
按照領域驅動設計,每次變更的時候,不是直接coding,而是把新需求,先放到領域模型裡,在領域模型裡設計,還原到真實世界。
領域驅動設計更適合老專案
是不是增加了工作量呢?
需要有一個支援領域驅動的底層架構
如何設計這樣一個底層架構?
在第三天的課裡
1.7 案例:遠端智慧醫療系統
對前面的思想進行實戰
1.7.1 期初:傳統的診所管理系統
護士接待患者,指引患者掛號,
然後由醫生去看
醫生建議患者去檢查,做B超、驗血
患者去交錢,驗血
醫生看報告,開藥
患者交錢去藥房拿藥
1.7.2 統一語言與領域建模
用客戶的語言,理解業務
1.7.3 事件風暴
迭代會議之前,開一個事件風暴會議
已確診和已開藥是否是同一個事件?
查詢醫生算不算一個事件?
只是個查詢,不需要記錄,預約了才要記錄
領域事件分析全了麼?還有已排班,已註冊
分析和事件相關聯人和事
預約是一個命令
觸發者 是患者
相關的還有預約時間
出診計劃,哪個醫生、哪個科室,什麼時間出診
梳理人和事的關係,
人和事是不是聚合
藥品明細和處方是一個部分和整體的關係,有聚合關係,貼一個紫色便籤
是不是聚合關係?
如果是聚合關係,部分的生命週期一定是在整體裡
比如,處方產生了,才有藥品明細,當處方刪除,藥品明細才會刪除
1.7.4 領域建模
2 DDD實踐篇:通過領域模型落地系統設計:資料庫、聚合、工廠與倉庫
2.1 將領域模型轉為資料庫設計
表、表之間的關係
2.2 將領域模型轉為程式設計
實體、值物件(不要太糾結)
實體:每個同學,有一個編號學號,
值物件:同學、老師
貧血模型的設計
充血模型的設計
充血模型的service,把訂單作為一個整體,訂單物件裡有依賴的其他物件的,定義了他們的關係。訂單service不需要處理訂單和訂單明細的依賴關係。
訂單service只需要儲存訂單,也不需要關心儲存到兩個表
訂單和訂單明細是聚合關係,訂單倉庫來做儲存到具體的表的事情。
查詢的時候,訂單工廠,會補查使用者、使用者地址等資訊
好處:
service不需要關注底層,只需要關注業務邏輯判斷
是不是要為每個領域物件設計一個倉庫和工廠?
框架
2.3 聚合
物件和物件之間有整體和不分關係的時候,只操作整體
訂單和訂單明細是整體與部分的關係。聚合關係
查詢和儲存操作都是對訂單,訂單明細的查詢和儲存操作在訂單裡完成
訂單就是聚合根
2.4 工廠(Factory)/倉庫(Repository)
2.5 領域驅動設計的分層架構
dao變成了倉庫,做了更具體的事情
2.6 網際網路轉型:遠端接診平臺
2.7 網際網路轉型帶來的陣痛
2.8 系統規劃與架構設計
網際網路轉型後的領域建模設計
CQRS命令查詢指責分離
2.9 四色建模法
通過介面卡,解耦業務程式碼和技術架構
總結
-
領域驅動設計適合大型複雜專案,不適合初始專案
-
領域驅動設計適合頻繁需求變更的專案
-
通過領域建模,劃分限界上下文,根據限界上下文拆分微服務
-
有新需求或者需求變更,先將需求放在領域模型內討論設計,再將領域模型轉為資料庫設計和程式設計
-
領域驅動設計時,可以採取事件風暴會議形式,和領域專家一起,使用統一語言討論,一起設計領域物件和關係
-
事件風暴會議需要確定一些事情:分析有哪些領域事件、確定有哪些和領域事件相關的人和事、確定觸發事件的命令、確定領域事件關聯的人和事有沒有聚合關係
-
將領域模型分配到各個限界上下文中,構建上下文地圖
-
新需求的程式碼寫在哪個模組裡,採用單一職責原則作為指導
-
單一職責中的職責是指引起軟體變化的一個原因
-
平時,就要整理程式碼,把同一個原因的程式碼放一起,不同原因的程式碼分開放
-
軟體退化的根源不是需求變更,而是在需求變更時,沒有及時調整程式碼,沒有正確的調整程式碼
-
貧血模型設計的程式碼,領域物件只有狀態,service層包含各種行為,service層很重
-
充血模型設計的程式碼,更符合面向物件,領域物件不僅封裝了狀態,還有各種修改狀態的行為,service層更輕,service層只處理業務邏輯的封裝、事務、許可權
作者: 元寶爸爸
出處:https://www.cnblogs.com/wozixiaoyao/p/11965398.html
版權:本文采用「署名-非商業性使用-相同方式共享 4.0 國際」知識共享許可協議進行許可。
覺得文章不錯,點個關注唄!