DDD - 開篇

  前言  

  最近再次拜讀了Eric的奠定之做【Domain-Driven Design –Tackling Complexity in the Heart of Software】,還有Vernon的【Inplementing Domain-Driven Design】,雖然是java版本,但並不影響閱讀,畢竟設計思想是通用的,結合我的使用DDD的一些經驗,作個隨談。html

  在我看來,DDD絕非什麼標新立異的的思想,更多的是軟件發展的天然結果。就像20世紀六七十年代出現的軟件危機後,面向對象編程被搬上了舞臺;瀑布式開發在快速發展的互聯網時代,敏捷成爲了它的救贖;而DDD更多的是對傳統的以數據爲中心的開發習慣的一種反思。java

  若是你關心軟件工藝,而不只僅是coding,那麼領域驅動設計即是很是重要的一項技能。程序員

  防軟件退化利器    

  隨着軟件業的快速發展,軟件規模愈來愈大,生命週期也愈來愈長,推倒從新開發的風險愈來愈大。這時,軟件團隊急需在較低成本的狀態下持續維護一個系統不少年。數據庫

  然而,事與願違,隨着時間的推移,程序愈來愈亂,維護成本愈來愈高,軟件退化成了無數軟件團隊的噩夢。編程

  咱們的軟件老是經歷着這樣的輪迴,軟件設計質量最高的時候是第一次設計的那個版本,當第一個版本設計上線之後就開始各類需求疊加和變動,這經常又會打亂原有的設計。架構

  特別是當咱們許多團隊都在實踐敏捷開發,但敏捷開發的落地對開發團隊的設計能力、設計質量,提出了很是高的要求。由於每一個敏捷週期,都是在對上一個版本的更新。若是設計質量跟不上,更新速度越快,代碼退化就越快。代碼質量降低了,還能敏捷得起來嗎?因此咱們如何在快速進行迭代交付的同時,又能保持着高質量的軟件設計呢?    分佈式

  現狀  

  長久以來,咱們程序員都是很好的技術型思考者,咱們老是擅長從技術的角度來解決項目問題。可是,一個軟件系統是否真正可用,是經過它所提供的業務價值體現出來的。微服務

  遺憾的是,咱們更多的開發人員,對DDD的實踐都是停留在"地面"上。學習

  過分拘泥於實現細節,而不是從一開始就居高臨下俯視咱們的軟件,會錯失讓咱們在天空概覽的機會。spa

  咱們開發人員老是在技術層面追求着高內聚,低耦合的完美設計,對不起,若是你不懂DDD在戰略層面在業務系統存在的意義,憑着戰術層面的指導,是實現不了這樣的完美設計的。  

   意義

  有沒有什麼方式可讓咱們保持軟件的質量呢?有,那就是領域驅動設計!

  首先DDD並非關於技術的,而是關於討論,聆聽,理解和發現業務價值。所以,與其天天鑽在那些永遠也學不完的技術中,何不將咱們的關注點向軟件系統所提供的業務價值方向思考,這也正是DDD所試圖解決的問題。

  DDD的核心理念中,是劃分爲戰略設計(天空)以及戰術設計(地面)兩部分的。  

  戰略設計主要從高層「俯視」咱們的軟件系統,幫助咱們精準地劃分領域,明確各個領域的邊界以及處理各個領域之間的關係;而戰術設計則從技術實現的層面教會咱們如何具體地實施DDD。

  能夠看出,戰略設計在整個DDD落地過程當中,是佔核心地位的,它給咱們提供了高屋建瓴的寬闊視野。  

  DDD的戰略設計幫助咱們清晰的劃分不一樣的業務系統和各自的業務關注點,這樣能夠有效的保護各自系統並實現高內聚低耦合的設計原則。   

   困境

  DDD理念面世這麼多年了,爲何業界內仍是不多實際的案例呢?我的認爲有幾點緣由:

  1. DDD提倡的是基於現實世界的現實行爲進行建模,這就限制了案例的產生,畢竟這是業界的核心業務,不太可能做爲案例披露出來的。

  2. 沒有好的領域專家,DDD一直強調領域專家的重要性,在咱們這個行業,業務和技術都深刻的,太少了,這個行業充斥着急功近利,沒有多少人真正是對某個行業進行鑽研透徹的。

  3. 概念繁多,對人的要求極高,特別是抽象能力,容易讓直性思惟的人繞進去,學習使用成本會比較高。

  4. 忽視戰略層面的意義,致使不少案例胎死腹中。

   即便是會面臨很多的困境,但DDD仍然是諸多公司追捧的寵兒,除了它能使咱們開發者提升抽象能力以外,DDD它自己的做用是簡單化,而不是複雜化。

  在使用DDD時,咱們應該採用最簡單的方式進行復雜領域建模,而不是使問題變得更加複雜。    

  突破的關鍵點

  當咱們在實施過程當中面臨着各類各樣的問題時,有哪些策略是能夠指導咱們進行專項突破的點嗎?  

  有的,從戰略設計先入手。

  上面提到了,咱們使用DDD,更多的是從戰術設計這個」地面「着手,因此會出現了DDD-Lite的狀況。而這是本末倒置的,DDD首先讓咱們關注的不是技術,而是業務語言。  

  領域劃分/限界上下文

   既然是領域驅動設計,那麼咱們的設計重點確定是在領域了,以及領域模型的正確設計了。

  首先領域並非很高深的詞彙,它是問題域集合的代名詞。咱們肯定咱們產品所屬的領域後,所面臨的問題是肯定的,好比說咱們是一個電商系統,它是屬於電商領域,那麼會遇到用戶,訂單,購物車,商品,交易,物流等明確的問題集合須要咱們解決,這些問題域是確切的。

  在領域驅動設計中,強調對於子域的正確劃分,即便是在平常開發中,咱們一般會也將一個大型的軟件系統拆分紅若干個子系統。這種劃分有多是基於架構方面的考慮,也有多是基於業務的。

  在DDD中,咱們對系統的劃分是基於領域的,也明確是基於業務的。即咱們能夠基於領域專家的領域業務知識,將整個系統劃分紅許多相對獨立的業務場景(子域),而後在一個一個的子域中進行領域模型分析與建模。

  而後咱們很快就發現了問題,哪些概念應該建模在哪些子域裏面?咱們可能會發現一個領域模型建模在子系統A中是能夠的,而建模在子系統B中彷佛也合乎情理。

  如何能正肯定於模型含義呢?限界上下文!

  限界上下文是一個顯式的邊界,領域模型便存在這個邊界內,建立邊界的緣由在於,每個模型概念,包括它的屬性和操做,在這個邊界內都是具備特殊含義的。  

  

   從這裏能夠看出,若是光憑名字,咱們是沒法區分兩個帳戶的意思的,只有經過它們所在的限界上下文,咱們才能看出它們之間的區別。

  限界上下文是用來爲領域提供語境的,它保證在領域以內的通用語言、領域模型有一個確切的含義,沒有二義性。

  行爲豐富的模型

  我一直認爲,DDD中的領域模型纔是一個真正意義上的OOP,它所推崇的充血模型,是映射着咱們真實世界的真實行爲。咱們平時口中所謂的OOP,實體只是單純的數據載體,沒有更多的功能,DDD推薦的領域對象,是跟咱們現實生活中的概念是一致的,有具體的行爲,是一個行爲飽滿的對象,這樣纔是DDD的威力所在,也是咱們實現高內聚低耦合的途徑。

  領域模型即業務。

  從DDD的名稱咱們就能夠看出,領域驅動設計中,領域模型是最核心的點所在,因此在設計獲得模型後,DDD要求咱們在代碼中無誤差地實現模型,也就是所謂模型驅動開發(Model-Driven-Design, MDD)。

  行爲豐富的領域模型,纔是DDD最大的威力,能設計出行爲豐富而且涵蓋諸多現實業務的模型,就是消化領域知識的最好體現。

  因爲這種模型是咱們現實世界的真實描述,鑑於咱們真實世界的知識跨度的速度(參考地心說的統治時間),是能夠維持軟件到必定的生命週期的。這種模型的行爲豐滿,符合真實世界的認知,且業務純淨,減小了犯錯的可能性。

  要建立行爲飽滿的領域對象並不難,首先出發點是認真思考咱們真實世界的可靠行爲,把這些行爲提煉到模型中,再次咱們須要轉變一下思惟,將領域對象當作是服務的提供方,而不是數據容器,結合真實世界多思考一個領域對象可以提供哪些行爲,而不是數據。

  DDD和微服務

  這幾年當DDD再次映入個人眼簾,是微服務的興起,DDD已經面世好多年了,隨着微服務的興起,DDD從新活躍在咱們的眼中,或者說,微服務的興起,也依賴了DDD的鋪墊。它們是相輔相成的。

  微服務的特色

  微服務的一個核心點就在於服務的劃分,整個系統被被分紅了不少個輕量的模塊,它的一個原則就是劃分出來的模塊在於「專」(小並非微服務的重要的考慮因素,具體參看【微服務架構 - 正確的開始】),即每一個服務的鬆散耦合上,也就是咱們常說的高內聚,低耦合。

  無獨有偶,DDD也是基於高內聚,低耦合的思想來指導咱們如何劃分正確的子域。

  限界上下文/上下文映射圖

  咱們上面講了,在限界上下文中,其中的領域模型都是高內聚的存在,它們的關聯性是很是強的,它們只會在同一個緣由的條件下進行軟件變化,因此一般狀況下,一個限界上下文下的子域是能夠設計爲一個微服務應用程序,而這個微服務的邊界,就是這個限界上下文,服務間的關係,就是上下文映射圖。

  在微服務中藉助DDD的思想劃分服務是大概這麼一個過程:

  • 按照限界上下文進行微服務的拆分,按照上下文映射圖定義各微服務之間的接口與調用關係;
  • 經過限界上下文的劃分,在各自的子域內進行建模,並基於充血模型或者貧血模型落地各個微服務的領域模型;
  • 按照領域模型設計各個微服務的數據庫;
  • 將以上的設計最終落實到微服務之間的調用、領域事件的通知。

  數據一致性

  在微服務中,會面臨着咱們分佈式系統的常見問題,其一就是事務的一致性。在DDD中,領域事件即可以用於處理這些問題,此時最終一致性取代了事務一致性,經過領域事件的方式達到各個組件之間的數據一致性。

  後續

  洋洋灑灑的聊了些我的對DDD的一些見解,其中的部分概念會後續在這個系列的博文章節裏繼續探討。

  DDD也不是"銀彈"

  正如微服務架構中的「微服務不是銀彈」,領域驅動設計也會面臨一樣的問題。做爲架構師,我始終認爲咱們在任何的狀況下對於任何的特定技術,均可以活學活用,因此我的使用DDD的一個理念的是,不要爲了DDD而去DDD。

  領域驅動設計做爲面向對象編程的高級方法論,它其中的不少設計是很是美妙以及契合實際的,然而所謂設計,是要以咱們的團隊的知識、經驗和智慧,全面充分的考慮各類內外因素後,在設計方案中做出合理的選擇的過程。

  咱們的目標是什麼?是追求完美的DDD嗎?不是,咱們的目標是把系統作得更健壯,賦予產品強大且持久的生命力,因此咱們在真正的使用過程當中,實際上是藉助了DDD不少的設計思想來指導咱們的系統設計。

  沒人在意你是不是一個純正的DDD,老闆以及用戶注重的,是你所使用的技術帶來的業務價值。

  因此在使用領域驅動設計時,並不表明整個系統的方方面面都必須聽從領域驅動設計的原則,須要根據實際狀況,讓適合的部分使用領域驅動設計,讓不適合的部分使用面向過程的設計。   

  DDD落地是一個深刻了解業務的過程

  DDD 的真諦是領域建模,即深刻理解業務。咱們不可能一步到位深入理解業務,它是一個逐步深刻的過程。只有深刻理解業務,將對業務的深刻理解設計到領域模型中,設計出來的軟件才更加專業。所以,基於每一個限界上下文進行領域建模,不斷地將每一個功能加入模型中,落地每一個微服務的設計。

  當業務愈來愈複雜,理解愈來愈深刻的時候,咱們要適時地調整原有的模型,就能適應新的功能。正由於 DDD 就是要應對的是軟件的這樣的不肯定性的複雜,纔會經過結合現實世界的理解,領域建模去抽象複雜業務,讓複雜業務獲得簡化,從而簡化軟件的設計,使設計始終處於高質量的水準上。

  所以,咱們學習 DDD,首先就要把設計作到位,準確理解那些領域,限界上下文,聚合、倉庫、領域事件等基礎概念,並在設計實戰中作出正確的設計。


   DDD中有不少概念是相對來講是比較抽象的,特別是對習慣邏輯思惟的程序員來講,摳概念是比較痛苦的,因此不少技術人員在初學DDD時,更多的是關注戰術層面的設計,然而過分地強調DDD的技術性將使咱們錯過由戰略設計帶來的好處,畢竟戰略層面能夠升個級爲整個軟件的業務架構,這個架構是支撐軟件生命週期重要的依據。    

  記住,領域模型的設計並不會一蹴而就,咱們須要反覆研究領域知識,不斷重構模型,才能將領域中的重要概念提煉成簡單而清晰的模型。

相關文章
相關標籤/搜索