1. 程式人生 > 其它 >談一談 DDD

談一談 DDD

隨著業務的不斷迭代和發展,使用者數量也在高速增長。市場和業務環境的多變,需求往往是複雜多變的,如何快速響應變更。需求變更一次,版本迭代一次,軟體就修改一次,軟體修改一次,質量就下降一次。不論第一次的設計質量有多高,軟體經歷不了幾次變更,就進入一種低質量、難以維護的狀態。需要設計一套易於擴充套件和維護的系統。

一、前言

最近 10 年的網際網路發展,從電子商務到移動互聯,再到“網際網路+”與傳統行業的網際網路轉型,是一個非常痛苦的轉型過程。在這個過程中,一方面會給我們帶來諸多的挑戰,另一方面又會給我們帶來無盡的機會,它會帶來更多的新興市場、新興產業與全新業務,給我們帶來全新的發展機遇。然而,在面對全新業務、全新增長點的時候,我們能不能把握住這樣的機遇呢?

隨著業務的不斷迭代和發展,使用者數量也在高速增長。市場和業務環境的多變,需求往往是複雜多變的,如何快速響應變更。需求變更一次,版本迭代一次,軟體就修改一次,軟體修改一次,質量就下降一次。不論第一次的設計質量有多高,軟體經歷不了幾次變更,就進入一種低質量、難以維護的狀態。需要設計一套易於擴充套件和維護的系統。

二、概述

2.1 什麼是DDD

DDD,全稱Domain-Driven Design, 是一種處理複雜領域的設計思想,它試圖分離技術實現的複雜性,並圍繞業務概念構建領域模型來控制業務的複雜性,以解決軟體難以理解,難以演進的問題。它通過邊界劃分將複雜業務領域簡單化,幫我們設計出清晰的領域和應用邊界,可以很容易地實現架構演進。

DDD將專案的主要焦點放在核心領域和領域邏輯上。基於一個模型進行復雜的設計,在技術和領域專家之間發起創造性的協作,迭代地切割問題的概念性核心。

DDD是面向物件的設計思想,是面向物件設計的一種昇華。

2.2 背景

2003 年埃裡克·埃文斯(Eric Evans)發表了《領域驅動設計》(Domain-Driven Design –Tackling Complexity in the Heart of Software)這本書,從此領域驅動設計(Domain Driven Design,簡稱 DDD)誕生。DDD 核心思想是通過領域驅動設計方法定義領域模型,從而確定業務和應用邊界,保證業務模型與程式碼模型的一致性。

但 DDD 提出後在軟體開發領域一直都是“雷聲大,雨點小”!直到 Martin Fowler 提出微服務架構,DDD 才真正迎來了自己的時代。
大部分的Java程式設計師開發生涯是從學習J2EE經典的分層理論開始的(Action、Service、Dao),在這種分層理論中,我們基本沒有啥機會使用那些所謂的“行為型”的設計模式,這裡的核心原因,就是J2EE經典分層的開發方式是“貧血模型”。

2.3 使用DDD的價值

  • 獲得了一個非常有用的領域模型
  • 業務得到了更準確的定義和理解
  • 領域專家可以為軟體設計做出貢獻
  • 更好的使用者體驗
  • 清晰的模型邊界
  • 更好的企業架構

領域專家、設計人員、開發人員通過領域模型進行交流,彼此共享知識和資訊,有利於溝通概念的統一,減少交流的障礙,防止需求變樣。

設計足夠精良且符合業務需求的領域模型能夠快速的響應需求變化。

軟體的本質就是對真實世界的模擬。因此,我們會有一種想法,能不能將軟體設計與真實世界對應起來,真實世界是什麼樣子,那麼軟體世界就怎麼設計。如果是這樣的話,那麼在每次需求變更時,將變更還原到真實世界中,看看真實世界是什麼樣子的,根據真實世界進行變更。這樣,日後不論怎麼變更,經過多少輪變更,都按照這樣的方法進行設計,就不會迷失方向,設計質量就可以得到保證,這就是“領域驅動設計”的思想。

2.4 實施DDD所面臨的挑戰

  • 為建立通用語言騰出時間和精力
  • 持續地將領域專家引入專案
  • 改變開發者對領域的思考方式

三、如何DDD

3.1 戰略設計與戰術設計

DDD的實施分戰略設計與戰術設計。

戰略建模:戰略設計主要從業務視角出發,建立業務領域模型,劃分領域邊界,建立通用語言的限界上下文,限界上下文可以作為微服務設計的參考邊界。戰略建模是以一種最巨集觀的角度去審視整個專案對它進行拆分,來劃分“界限上下文”,最終形成一個具有俯瞰視角的“上下文對映圖”。

戰術建模:戰術設計則從技術視角出發,側重於領域模型的技術實現,完成軟體開發和落地,包括:聚合根、實體、值物件、領域服務、應用服務和資源庫等程式碼邏輯的設計和實現。

在實施過程中,我們需要明確“通用語言”,通用語言和限界上下文(Bounded Context)同時構成了DDD的兩大支柱,並且它們是相輔相成的。

通用語言是以一種領域專家、設計人員、開發人員都能理解的語言作為相互交流的工具,在不斷交流的過程中發現和挖出一些主要的領域概念,然後將這些概念設計成一個領域模型。由領域模型驅動軟體設計,用程式碼來表現該領域模型。領域需求的最初細節,在功能層面通過領域專家的討論得出。

領域模型貫穿軟體分析、設計,以及開發的整個過程;領域專家、設計人員、開發人員通過領域模型進行交流,彼此共享知識與資訊;因為大家面向的都是同一個模型,所以可以防止需求走樣,可以讓軟體設計開發人員做出來的軟體真正滿足需求。

在這個過程中,需要業務專家的參與,他們才是最懂業務的人,他們能用他們已有的對這個領域的知識,與我們一起設計開發系統,讓我們的系統更符合實際需要。典型的例子,在設計一個系統時,如果兩個物件或模型有關聯關係,那麼這個關聯關係是一對多、一對一還是多對多,有時我們並不能很好的判斷出來,這個時候就需要領域專家應用他們的知識來幫助我們一起處理這部分的設計。

領域專家並不是一個職位,他可以是精通業務的任何人。可能是軟體產品的設計者,甚至可能是銷售員。
在設計的過程中,我們書面設計的文件不可能面面俱到,應儘量將文件減至最少,並且主要用它來補充程式碼和口頭交流,解釋我們模型中的概念,避免文件與專案脫節,設計的重要細節應該在程式碼中體現出來。

3.2 DDD領域模型

DDD的研究方式與自然科學的研究方法類似,下面以研究一棵樹的過程舉例

  • 第一步:確定研究物件,即研究領域,這裡是一棵桃樹。
  • 第二步:對研究物件進行細分,將桃樹細分為器官,器官又分為營養器官和生殖器官兩種。其中營養器官包括根、莖和葉,生殖器官包括花、果實和種子。桃樹的知識體系是我們已經確定要研究的問題域,對應 DDD 的領域。根、莖、葉、花、果實和種子等器官則是細分後的問題子域。這個過程就是 DDD 將領域細分為多個子域的過程。
  • 第三步:對器官進行細分,將器官細分為組織。比如,葉子器官可細分為保護組織、營養組織和輸導組織等。這個過程就是 DDD 將子域進一步細分為多個子域的過程。
  • 第四步:對組織進行細分,將組織細分為細胞,細胞成為我們研究的最小單元。細胞之間的細胞壁確定了單元的邊界,也確定了研究的最小邊界。

在領域不斷劃分的過程中,領域會細分為不同的子域,子域可以根據自身重要性和功能屬性劃分為三類子域,它們分別是:核心域、通用域和支撐域。決定產品和公司核心競爭力的子域是核心域,它是業務成功的主要因素和公司的核心競爭力。沒有太多個性化的訴求,同時被多個子域使用的通用功能子域是通用域。還有一種功能子域是必需的,但既不包含決定產品和公司核心競爭力的功能,也不包含通用功能的子域,它就是支撐域。核心域、支撐域和通用域的主要目標是:通過領域劃分,區分不同子域在公司內的不同功能屬性和重要性,從而公司可對不同子域採取不同的資源投入和建設策略,其關注度也會不一樣。

3.3 限界上下文

限界上下文用來確定語義所在的領域邊界,限界就是領域的邊界,而上下文則是語義環境。通過領域的限界上下文,我們就可以在統一的領域邊界內用同意的語言進行交流。

比如電商領域的商品一樣,商品在不同的階段有不同術語,在銷售階段是商品,而在運輸階段則變成了貨物。同樣的一個東西,由於業務領域的不同,賦予了這些術語不同的涵義和職責邊界,這個邊界就可能會成為未來微服務設計的邊界,所以領域邊界就是通過限界上下文來定義的。

所以,在微服務中,每個領域模型都有它對於的限界上下文,團隊在限界上下文內通用語言交流。領域內所有限界上下文的領域模型構成整個領域的領域模型。

3.4 運用單一職責原則

單一職責原則:軟體系統中的每個元素只完成自己職責範圍內的事,而將其他的事交給別人去做,我只是去呼叫。

“一個職責就是軟體變化的一個原因”是著名的軟體大師 Bob 大叔在他的《敏捷軟體開發:原則、模式與實踐》中的表述。

單一職責原則要求我們在維護軟體的過程中需要不斷地進行整理,將軟體變化同一個原因的程式碼放在一起,將軟體變化不同原因的程式碼分開放。

四、總結

深刻理解 DDD 的設計思想和內涵,把握好邊界和分層這個大原則,結合企業文化和技術特點,靈活運用戰術設計方法,選擇最適合的技術和方法解決實際問題。

在每次變更的時候,先回到領域模型,基於業務進行領域模型的變更。然後,再基於領域模型的變更,指導程式的變更。這樣,不論經歷多少次需求變更,始終能夠保持設計質量不退化。這樣的設計,才能保障系統始終在低成本的狀態下,可持續地不斷維護下去。

參考資料

  • 《領域驅動設計——軟體核心複雜性應對之道》
  • 《實現領域驅動設計》
  • DDD實戰課(歐創新)

__EOF__

 


 

歡迎轉載,但請註明出處!
歡迎大家一起交流學習!如果有什麼疑問,大家可以在評論區一起交流!
如果您覺得文章對您有幫助,可以點選文章右下角【推薦】一下。您的鼓勵是我的最大動力!