聊一聊中台和DDD(領域驅動設計)

  • 2021 年 8 月 26 日
  • 筆記

本次分享價值:本次分享主要針對中台、微服務和領域模型的理念、本質及其構建方法論進行探討。對領域分析的價值所在就是尋求「千變萬化」中相對的「穩定性、第一性」,然後通過合理的架構分析及抽象隔離業務的複雜度和技術複雜度,隔離業務領域的穩定性和易變性,從架構上精巧、快速的支撐業務的變化。

中台到底是什麼?

中台的概念最早是從阿里流傳出來的,阿里的中台戰略是從業務中台和數據中台開始的,採用業務中台和數據中台相結合的雙中台建設模式。後來也有人提出技術中台,AI中台等等。

在阿里完美落地中台之後,很多企業開始對阿里對標。完成大一統的集中式系統拆分,實現了從傳統應用向大平台的演進。但是每個企業對中台的理解,也都不一樣,那麼阿里的中台到底是什麼樣的?

阿里業務中台的前身是共享平台[//cloud.tencent.com/developer/article/1780514],而原來的共享平台更多的是被當作資源團隊,承接各業務方的需求,並為業務方在基礎服務上做定製開發。阿里業務中台的目標是把核心服務鏈路(會員、商品、交易、營銷、店鋪、資金結算等)整體當做一個平台產品來做,為前端業務提供的是業務解決方案,而不是獨立的系統。這種能力有別於傳統的煙囪的系統建設方式。

說到這裡,那麼中台到底是什麼呢?

其實不同人不同團隊對於中台的定位和理解是存在很大爭議的。

我們先看下阿里對中台的定義:中台是一個基礎的理念和架構,我們要用中台的思想建設、聯通所有基礎服務,共同支持上端的業務。業務中台更多的是支持在線業務,數據中台則提供基礎數據處理能力和很多的數據產品供所有業務方使用。即業務中台、數據中台和算法中台等一起提供對上層業務的支撐。

我們可以看到關於中台的幾個關鍵詞:共享、聯通、融合和創新。

聯通是前台和中台之間各業務版本的聯通。

融合是前台企業級業務流程和數據的融合,並以共享的方式支持前台一線業務的發展和創新。

其實我對中台的理解就是,中台首先體現的是一種企業級的能力,他提供的是一套企業級的整體解決方案,解決小到企業、集團,大到生態圈的能力共享、業務聯通和融合的問題,支持業務和商業模式的創新。通過平台聯通、業務和數據融合,為前台用戶提供一致體驗,更敏捷的職稱前台一線業務。

中台來源平台,但於平台相比,中台更多的是一種理念的轉變,它主要體現在這三個關鍵的能力上。

1、對前台業務的快速響應能力。

2、企業級的復用能力。

3、從前台、中台到後台的設計、研發、頁面操作、流程、服務和數據的無縫聯通、融合的能力。

微服務設計為什麼要選擇DDD?

其實最近幾年微服務架構的思想越來越普及,很多企業已經或者嘗試從單體架構向微服務架構轉型。微服務也成為很多中大型企業實施中台戰略的不二之選。但是在微服務實施過程中有很多問題,單體應用到底應該如何去拆分微服務?邊界到底怎麼劃分?微服務這個微字到底如何衡量,到底拆成到什麼粒度合適?微服務應該如何設計?對於這類問題,不同團隊不同人都有自己的經驗和對微服務的理解,各執一詞,那麼有沒有適合的理論或者設計方法來知道微服務設計呢?

軟件架構的演進史

軟件的架構模式大體來說經歷了從單機、集中式到分佈式微服務架構三個階段的演進。

![image-20210726183504350](/Users/wangzhongyuan/Library/Application Support/typora-user-images/image-20210726183504350.png)

第一階段:單機架構,這個階段通常採用面向過程的設計方法,通常採用C/S架構,大多採用結構化編程方式,

第二階段:集中式架構,這個階段通常採用面向對象的設計方法。一般採用經典的三層架構,系統包括業務接入層、業務邏輯層和數據庫層。這種設計模式往往容易使系統變得臃腫,可擴展性和彈性伸縮能力差。

第三階段:分佈式微服務架構,該架構可以是實現業務和應用之間的解耦,解決集中式單體應用擴展性和彈性伸縮能力不足的問題,更加適合雲計算環境下的部署和運營。

微服務拆分和設計的困境

微服務架構的引入,的確解決了單體應用的很多問題,比如擴展性、彈性伸縮能力、小規模團隊的敏捷開發等。但是在微服務實踐過程中,也產生了不少爭論和疑惑,比如微服務的粒度如何把握?微服務到底如何拆分和設計呢?微服務的邊界到底應該在哪裡?

可以說,很久以來都沒有一套系統的理論和方法來知道微服務的拆分和設計。微服務拆分困境產生的根本原因,就是不知道業務或者應用的邊界到底在什麼地方。換句話說,如果確定了業務邊界和應用邊界,這個困境也就迎刃而解的。

其實有時候微服務設計的重點不在於微服務的大小,也不在於拆分了多少個微服務,而是在於微服務內部的邊界是否清晰,這些邊界是否進行了有效的隔離,以及這些微服務上線後能否隨着業務的發展輕鬆實現業務模型和微服務架構的演進,所以,在微服務設計時,我們要考慮微服務拆分的大小,也要關注微服務內部的邏輯邊界。

微服務設計強調從業務領域出發,因此我們第一步要做的就是先劃分業務的領域邊界,然後在這個邊界內構建業務的領域模型,根據領域模型來完成從單體應用到微服務的建設。

那麼如何確定業務和應用的邊界?是否有理論或知識體系來知道呢?

那就是DDD!

DDD也就是領域驅動設計,2003年Eric·Evans出版了《領域驅動設計》這本書之後,DDD誕生。DDD的核心思想就是從業務角度出發,根據限界上下文劃分業務的領域邊界,定義領域模型,確認業務邊界。在微服務落地時,建立業務領域模型和微服務代碼模型的映射關係,從而保證業務架構和微服務系統架構的一致性。但DDD提出後在軟件開發領域一直都是雷聲大,雨點小。直到Martin Fowler提出微服務架構後,DDD才迎來了自己的時代。

為什麼DDD適合微服務

首先DDD是一種處理高度複雜領域的設計思想,一種結構設計方法,它試圖分離技術實現的複雜性,並圍繞業務概念構建領域模型來控制業務的複雜性,以解決軟件難以理解,難以演進的問題。

而微服務是一種架構風格,兩者從本質上都是為了追求軟件的高響應力,從業務視角去分離應用系統建設複雜度的手段。兩者都強調從業務領域觸發,根據業務的發展,合理規劃業務領域邊界,採用分治策略,降低業務和軟件開發的複雜度,持續調整現有架構,優化現有代碼,以保持架構和代碼的生命力,也就是我們常說的演進式架構。

那為什麼說DDD適合微服務呢?我們可以通過DDD戰略和戰術設計方法,劃定業務領域邊界,構建領域模型,用領域模型指導微服務拆分和設計,解決微服務的業務和應用邊界難以劃分的難題,同事解決微服務落地時設計的難題。

另外,更關鍵的一點是,DDD不僅可以指導微服務的邊界劃分和設計,也可以很好地應用於企業中台的領域建模設計,幫你建立一個邊界清晰、可高度復用的企業級中台業務模型,完成微服務的落地。

那是不是說,只有微服務系統才使用用DDD呢?

DDD不僅適用於微服務拆分和設計,同樣也適用於單體應用。如果單體應用採用了DDD方法設計,當某一天你想將單體應用拆分為多個微服務時,你會發現採用DDD 方法設計出來的單體應用,拆分起來比採用傳統三層架構設計出來的單體應用容易很多。這是因為用DDD方法設計的單體應用,在應用內部會有很多聚合,聚合之間是松耦合的,但聚合內部的功能具有高內聚的特點。有了這一層清晰的聚合邊界,我們就可以很容易完成從單體應用向微服務的拆分了。

DDD、中台和微服務的關係

DDD和微服務源於西方,而中台來自於阿里,三者看起風馬牛不相及,實則緣分匪淺。中台是抽象出來的業務模型,微服務是業務模型的系統實現,DDD作為方法論可以同時知道中台業務建模和微服務建設,三者相輔相成,完美結合。

你可能會疑惑,為什麼DD都可以同時指導中台和微服務建設呢?這是因為DDD有兩把利器,那就是它的戰略設計和戰術設計方法。

![image-20210726191646742](/Users/wangzhongyuan/Library/Application Support/typora-user-images/image-20210726191646742.png)

中台在企業架構上更多的是偏向業務架構,形成中台的過程實際上也是業務領域不斷細化和能力沉澱的過程。在這個過程中我們會對同類通用的業務能力進行聚合和重構,再根據限界上下文和業務內聚的原則建立領域模型。DDD戰略設計最擅長的就是領域建模。

在中台完成領域建模後,DDD戰略設計構建的領域模型就可以作為微服務設計的輸入。此時,限界上下文和領域模型可以作為微服務拆分和設計的邊界和依據,所以,DDD的戰術設計又恰好可以與微服務設計完美無縫結合。

可以說,業務中台和微服務正是DDD實戰的最佳場景。

DDD的基本原理

在DDD的知識體系里有很多概念,比如領域、子域、核心子域、通用子域、支撐子域、限界上下文、聚合、聚合根、實體、值對象、領域服務和應用服務等。他們在DDD理論和知識體系里都是非常重要的概念。

什麼是領域和子域

領域,名詞解釋是「領域是從事一種專門活動或事業的範圍、部類或部門」,在DDD中領域就是用來確定範圍的,範圍即邊界。

在研究和解決業務問題時,DDD會按照一定的規則對業務領域進行細分,當領域細分到一定的程度後,DDD會將問題範圍限定在特定的邊界內,在這個邊界內建立領域模型,進而用代碼實現該領域模型,解決響應的業務問題。簡而言之,DDD的領域就是這個邊界內要解決的業務問題域。

子域,既然領域是用來限定業務邊界和範圍的,那麼就會有大小之分,領域越大,業務邊界的範圍就越大,泛指則相反。領域可以進一步劃分為子領域。我們把劃分出來的多個子領域稱為子域,每個子域對應一個更小的問題域或者更小的業務範圍。

什麼是限界上下文

在DDD領域建模過程中,會有很多項目參與者,不同人對同樣的領域知識會有不同的理解。而且有時候同一領域內的名詞和術語也可能不統一,團隊成員交流起來會出現障礙,嚴重時甚至會傳達錯誤的信息。

在DDD中有「通用語言」和「限界上下文」這兩個重要概念。兩者相輔相成,通用語言用於定義上下文對象的含義,而限界上下文則用於定於領域邊界,以確保每個上下文對象在它特定的邊界內具有唯一的定義,在這個邊界內,組合這些對象構建領域模型。

什麼是通用語言:通過團隊交流達成共識的,能夠簡單、清晰、準確地描述業務含義和規則的語言就是通用語言。通用語言中的名詞一般可以給領域對象命名,比如貨源、訂單等,他們對應領域模型中的實體對象。而動詞則表示一個動作或領域事件,如果下單,訂單支付,它們對應領域模型中的領域事件或者命令。

限界上下文:為了避免同樣的概念或語義在不同的上下文環境中產生歧義,DDD在戰略設計上提出了「限界上下文」這個概念,用來確定語義所以的領域邊界。「限界」是指具體的領域邊界,而「上下文」則是業務語義所在的上下文環境。

定義:限界上下文就是在限定的上下文環境內,用來封裝通用語言和領域對象,保證領域內的一些術語、領域對象等有一個確切的含義,沒有語義二義性的一個業務邊界。

舉個例子,企業在設置組織架構時,就是在定義企業的限界上下文邊界。而且往往會從企業的職能邊界出發,根據這些只能邊界來設置部門,劃定部門的邊界,比如:可以為人力資源管理相關設置人力資源部,為財務核算管理相關的職能設置財務部門等等。

什麼是實體和值對象

DDD戰術設計中有兩個重要的概念:實體(Entity)和值對象,兩個都是領域模型中非常重要的基礎領域對象。

實體:在DDD的領域模型中有這樣的一類對象,它們擁有唯一標識符,並且他們的標識符在歷經各種狀態變更後仍能保持一致。對這些對象而言,重要的不是屬性,而是其延續性和標識,這種對象的延續性和標識會跨越升值超過軟件的生命周期。我們把領域模型中這樣的領域對象成為實體。

在代碼模型中,實體的表現形式就是實體類。這個類包含了實體的屬性和方法,通過這些方法實現實體自身的業務行為和業務邏輯。這些實體通常採用充血模型,與實體相關的所有業務邏輯都在實體類方法中實現,跨多個實體的領域邏輯則在領域服務中實現。

值對象:相對實體而言,值對象會更加抽象一些,我們來看下《實現驅動領域設計》中對值對象的定義。值對象是通過對象屬性值來識別的對象,它將多個相關屬性組合成一個概念整體,用於描述領域的某個特定方面,並且是一個沒有標識符的對象。

也就是說,值對象描述了領域中的某一個東西,這個東西是不可變的,它將不同的關聯屬性組合成了一個概念整體。舉個例子人員實體:包括姓名,年齡,性別及人員所在的省、市、縣和街道等屬性。這樣在人員實體中,顯示地址的多個屬性就會顯得很零碎。所以,我們把「省、市、縣和街道」等屬性拿出來,構成一個地址的屬性集合,這個屬性集合的名稱就是地址值對象。

![image-20210726212142445](/Users/wangzhongyuan/Library/Application Support/typora-user-images/image-20210726212142445.png)

什麼是聚合和聚合根

在DDD中實體和值對象是很基礎的領域對象。但實體和值對象知識個體化的業務對象,他們所表現出來的是個體的行為和能力,在領域模型中我們需要一個這樣的組織,將這些緊密關聯的個體對先聚集在一起,按照組織內統一的業務規則共同完成特定的業務功能,因此就有了聚合的概念

聚合:領域模型內的實體和值對象就類似這些組織中的個體,而能讓實體和值對象協同工作的組織就是聚合。換句話說,從技術的角度,聚合是有業務和邏輯緊密關聯的實體和值對象組合而成的。

聚合根:聚合內有一定的業務規則以確保聚合內數據的一致性,如果在實現業務邏輯時,任由服務對聚合內實體數據進行修改,那麼很可能會因為在數據變更過程中失去統一的業務規則控制,而導致聚合內實體之間數據邏輯的不一致。所以引入了聚合根,聚合根的主要目的是避免聚合內由於複雜數據模型缺少統一的業務規則控制,而導致聚合內實體和值對象等領域之間數據不一致的問題。也就是說,在聚合根的方法或領域服務中可以用上這些業務規則,來確保聚合內數據變更時可以保持數據邏輯一致性。

如果把聚合比作組織,那聚合根就是這個組織的負責人。聚合根就是這個組織的負責人。聚合根也稱為根實體,但它不僅是實體,還是聚合的管理者。

什麼是領域事件

在領域建模時,我們發現除了命令和操作等業務行為以外,還有一類非常重要的事件。這類事件發生後通常會觸發進一步的業務操作,在DDD中這類事件被稱為領域事件。

舉例來說,領域事件可以是業務流程的一個步驟,比如下單成功就會去觸發下架貨源,也可以是定時觸發的事件,也可以是一個事件發生後觸發的後續動作等等。

領域事件採用事件驅動架構設計,可以切斷領域模型之間的依賴關係,在領域事件發佈後,事件發佈方不必關心訂閱方的事件處理是否成功。這樣就可以實現領域模型的解耦,維護領域模型的獨立性。當領域模型映射到微服務時,領域事件就可以解耦微服務,這時微服務之間的數據就可以不再要求強一致,而是基於最終一致性。

小結

聚合、聚合根、實體和值對象是領域層聚合內非常重要的領域對象,他們之間具有很強的關聯性。聚合里包括聚合根。實體、值對象和領域服務等,他們共同按照聚合的業務規則完成聚合的核心領域邏輯。

總結下他們之間的聯繫和區別。

聚合的特點:聚合內部業務邏輯高內聚,聚合之間滿足低耦合的特點。聚合是領域模型中最小的業務邏輯邊界。聚合是領域模型中可拆分為微服務的最小單位,可以按照聚合獨立拆分成一個微服務,但主要不要過度拆分,這樣會增加運維和集成成本。

聚合根的特點:聚合根是實體,有實體的特點,擁有全局唯一標識,有獨立的生命周期。一個聚合只有一個聚合根,聚合根在聚合內對實體和值對象通過對象引用的方式進行組織和協調,聚合與聚合之間只能通過聚合根ID引用的方式,實現聚合支架的訪問和協同。

實體的特點:實體有ID標識,通過ID判斷相等性,ID在聚合內唯一即可。實體的狀態可變,他依附於聚合根,其生命周期由聚合根管理。實體一般會持久化,但與持久化對象不是一對一的關係。實體可以引用聚合內的聚合根、實體和值對象。

值對象的特點:值對象沒有ID,且數據不可變,他沒有生命周期,用完即扔。值對象通過屬性值判斷相等性。它是一組概念完成的屬性組成的集合,用戶描述實體的狀態和特徵,其核心本質是「值」。

DDD的分層架構

微服務的架構模型有好多種,有洋蔥架構,CQRS和六邊形架構等。雖然這些架構模式提出的時代和背景不同,但其核心理念都是為了設計出「高內聚,低耦合」的微服務。DDD分層架構的出現,使微服務的架構邊界變得越來越清晰,在微服務架構模型中,佔用非常重要的位置,那麼到底DDD的分層架構時什麼樣的?

我們看下DDD架構的發展與演進。

![image-20210727163430153](/Users/wangzhongyuan/Library/Application Support/typora-user-images/image-20210727163430153.png)

用戶接口層常見解釋是這樣的,用戶接口層負責向yoghurt展示信息的和解析用戶指令,這裡的用戶可能是用戶、程序、自動化測試和批處理腳本等。

用戶接口層主要facade接口、DTO以及DO數據的組裝和轉換等代碼邏輯。主要作用就是避免暴露微服務的業務邏輯,導致數據外泄,不能將後端對象的所有屬性數據,不加區分的暴露給所有前端應用。更不能因為前端應用不同的數據展示需求,而在後端定製開發出多個不同的應用服務或領域服務,這樣會產生大量重複代碼,也容易導致業務邏輯混亂,代碼可維護性變差。

應用層:連接用戶接口層和領域層,他是很薄的一層,主要職能就是協調領域層多個聚合完成服務的組合和編排。但切記不要將本應該在領域層的核心領域邏輯在應用層時間,這會使得領域模型失焦,時間一長就會導致應用層和領域層的邊界變得混亂,邊界清晰的四層架構滿滿就可能演變成業務邏輯複雜的三層架構了。

領域層:領域層位於應用層之下,是領域模型的核心,主要實現領域模型的核心業務邏輯,體現領域模型的業務能力。領域層用於表達業務概念、業務狀態和業務規則,可以通過各種業務規則校驗手段保證業務的正確性。領域層主要關注實現領域對象或者聚合自身的原子業務邏輯,不太關注外部用戶操作或者流程等方面的業務邏輯。

基礎層:基礎層貫穿了DDD所有層,它的主要職能就是為其他各層提供通用的技術和基礎服務,包括第三方服務,驅動,消息中間件,網關,文件,緩存以及數據庫等。

重要原則:每層只能與其下方的層發生耦合。

中台領域和微服務建設方法論

如何用事件風暴構建領域模型

前面我們說過微服務設計為什麼要選擇DDD,最重要的一點就是可以用DDD方法建立的領域模型,清晰地劃分微服務邏輯邊界和物理邊界。

那麼我們應該採用什麼樣的方法,去構建領域模型呢?下面就在DDD戰略設計中常使用的一種方法:事件風暴

事件風暴是在2013年由老外提出來的,事件風暴是一項團隊活動,領域專家與項目團隊通過頭腦風暴的形式,羅列出領域中所有的領域事件、整合之後形成最終的領域事件集合,然後,為每一個事件標註出導致該事件的命令,再為每一個事件標註出命令發起方的角色。命令可以是用戶發起,也可以是第三方系統調用或者定時器觸發等,最後對事件進行分類,整理出實體、聚合、聚合根以及限界上下文等,在限界上下文邊界內構件領域模型。

另外事件風暴過程也是建立團隊通用語言的過程,這個過程對項目團隊確定項目建設目標,完成業務領域模型分析,系統建設和落地非常重要。

領域建模的關鍵過程包括:產品願景分析、場景分析、領域建模、微服務拆分與設計等幾個重要階段。

如何用DDD重構中台業務模型

如何用DDD設計微服務代碼模型

下單重構案例經驗分享

案例比較。申請單系統遇到的一些問題。