1. 程式人生 > >領域驅動設計(DDD)- 請先搞清楚一些概念

領域驅動設計(DDD)- 請先搞清楚一些概念

責任 可能 升級 是你 ora ext 計數 方法 避免

開發一個新系統

  一般我們開始開發一個商業系統都需要做什麽?讀需求文檔去查找功能點,拆解任務。多數情況下,拆解項目是為了評估工作,做評估、分配任務到個人、設計數據庫結構,然後就開始了Coding。

所以,這種方式怎麽樣?我們是否已經做的很好了??

想想近幾年通過這種方式做的項目是否都有下面一些問題呢?

  1. 你的項目在一些地方有著相同的實現
  2. 對同一個東西有著不止一個的對象
  3. 有些對象的屬性並不是真實的屬性
  4. 各個對象相互之間沒有或者有很小的關聯
  5. 看看你的項目是不是很難理解項目的真正意圖

  我肯定你經常遇到上面的問題,你知道為什麽會出現這些問題麽?原因是傳統的方式指導我們自下而上的設計整個系統,而不是嘗試著自上而下的設計系統。當你設計一個系統,你需要整個程序將要做什麽,客戶想要達到什麽樣的目標,那麽從頂層目標開始設計會讓你最終達到預定的目標。

  但是當你從底層開始設計的時候,你會從細微處開始設計,你只有一點或者沒有任何關於頂層怎麽使用或者頂層的功能到底是怎樣的。

  你是否聽說過有些開發者說他們對整個領域的知識並不清楚,那是必然的,因為整個程序的設計並不能體現整個領域,並且開發者只了解他們工作的那個部分,這是很悲催的事情。。。

  那麽,傳統的方式-“數據庫優先的開發方式”應該被遺棄麽?並不是這個意思,但是當你面對一個復雜的系統,這種自下而上的設計並不能提供一個好的面向對象的處理方式。

那麽,好的解決方案是什麽?

解決方案就是 DDD(DOMAIN DRIVEN DESIGN)。

什麽是DDD?

領域驅動設計(Domain-driven design 縮寫DDD)不是一種技術或者方法,DDD提供了一種實踐性的指導原則,用來解決和加速處理復雜領域的軟件項目 -維基百科。

本文涉及的概念:

  1. 理解領域(Domain)
  2. 通用語言(Ubiquitous Language)
  3. 上下文和有界上下文(Contexts and Bounded Context)
  4. 實體和值對象(Entities and Value Objects)
  5. 聚合和聚合根(Aggregates and Aggregate Roots)
  6. 持久化透明(Persistence Ignorance)
  7. 倉儲(Repository)
  8. 領域服務(Domain Service)

本文只是對這些感念進行理解,並不提供任何可用的代碼。

理解領域

領域是一定範圍內的知識、活動、影響。用戶用程序去解決、處理的領域就是軟件的領域。

領域就是一個概念,你能說出你現在做的程序的領域是什麽?,你能說說優酷網站的領域是什麽麽?

本文就利用生活中真實的例子來讓你體驗怎麽用領域來驅動你去分析你的項目。這個例子可能並不與開發有關,但它們對讓你適應上而下的去思考是很有幫助的,同時也過一遍DDD的技術要點。

如果說你要蓋一棟房子,那麽你需要以下的東西

  • 有一塊地
  • 樓共有6層
  • 每層有4個套房

那麽你的領域是什麽呢?

領域是房子麽?可能,但是你應該知道,如果你把房子作為你的領域,那麽你可能會忽略很多的小的需求。你設計的房子必須設計那裏是讓人住的。那麽,一般而言的“房子”可能會讓我們忽略一些細節,所以,我們應該縮小我們的領域,那就是“民房”。

那麽,當你和建築工人或買房子的人說起你設計的房子時,你所說的“民房”就可以很容易的被人理解了。當承包商告訴你要設計一個6層每層4套房子的時候,在語言上你是否稍微修改了一下呢?現在如果你讓建築工人到一個地方建“房子”,他們可能並沒有考慮到一些“民房”的一些特性。但是如果你說了“民房”呢,他們肯定會做出合理的分析。

這就是我們將要說到的“通用語言”

通用語言(Ubiquitous Language)

概念很簡單,程序員和銷售應該公用同一種兩個人都理解的語言,更重要的是,應該使用商業術語而不是技術術語。

更多的“通用語言”的例子:

例1:

錯誤的語言:

小臥室的長寬比應該是4:3

正確的語言:

兒童臥室長度因該是20尺,寬度應該是15尺。

從這可以看到,對於房主來說“小臥室”,“長寬比”這些都屬於技術術語,對他們來說兒童房、客廳、起居室等才是更易理解的詞語。很明顯尺寸對房主來說更為有意義。

例2:

來看看軟件上的一些例子。

錯誤的語言:

在搜索功能上,我們應該考慮Sql Server的“詞幹分析器”和“同義詞庫”來讓我們的搜索更合理,另外我們也應該添加排除詞,讓搜索更精確。

從這裏可以看到,如果你的領域專家可能不是個技術型,那麽他很有可能不理解“詞幹分析器”和“同義詞庫”等。

正確的語言:

在搜索功能上,我們應該考慮搜索詞的同義詞可以讓結果有更多的相關數據,而且我們不應該區別對待數字的奇偶,大小寫,分詞等,我們應該忽略掉所有的沒有意義的幹擾字。

你能看到這些語言的不同之處麽?一個正確的語言可以讓圈內的所有人都以相同的方式理解這些觀點。

我們再說說“民房”吧。如果你將設計民房的所有事情當作一個任務並放在一起處理的話,你認為這樣明智麽?很明顯,如果你將這些作為一個工作單元的話,你可能會錯過一些東西。設計一個房子有很多相關聯的設計,例如,你需要考慮通風,多功能,停車空間,社區等。

正如你所看到的,不同的上下文就出現了,這就是“上下文”和“有界上下文”出現在領域驅動設計的原因了。

“上下文”和“有界上下文”

一個有界上下文可以是一個很小的程序,包括他自己的領域,自己的代碼和自己的存儲機制,在一個上下文裏,他們應該在邏輯上一致,每個有界上下文應該獨立於其他的有界上下文。

更多的有界上下文例子:

考慮一下電商系統,最初你可以認為他是一個商店上下文,但是你看的更細點,你會發現其他的上下文,例如:庫存,物流,賬戶等。

合理的拆分一個大型的有界上下文可以讓你的應用程序模塊化,並且讓你區分不同的關註點,而且讓應用程序更易於管理和升級。每個有界上下文都有相應的責任和操作。合理的上下文劃分可以讓我們更容易的找到邏輯所在的位置,從而避免“大泥球”。

什麽是“大泥球”(BBOM,Big ball of mud)

大泥球是一個不規則的、雜亂的、松散的泥巴,這類系統是典型的高度重復,快速修復,無意義增長的系統。混亂的消息傳遞,在一個地方幾乎所有的重要信息都是全局的和重復的,所有的系統架構都可能沒有被很好的定義。

我們的目標是避免所有的BBOM

我們還來說說“民房領域”吧,我們有幾個有界上下文:

  • 電力供應
  • 停車位
  • 套房
  • 等等

詳細說一下“套房”吧,套房是由不同的房間組成,每個房間又有不同的門窗。那麽現在關於屋裏面的窗戶就有兩個問題了:

  問題1:你可以想象出來沒有屋子的窗戶麽?

  問題2:如果一個窗戶沒有了容納他的屋子,那麽它有沒有唯一的標識?

回答上面的問題會揭示出DDD中下面的概念:

  1. 實體(Entity)
  2. 值對象(Value Object)
  3. 聚合和聚合根(Aggreates & Aggrate root)

實體

“這是我的實體,那裏還有許多,但是這個是我的!”

定義實體的關鍵是實體是有“唯一標識”(Identity)的,唯一標識在系統中標識,無論兩個實體是多麽的相似,他們都是不同的實體。

例如:

  1. 你家的臥室
  2. 博客網的文章
  3. 博客網的用戶

值對象

定義值對象的關鍵是值對象沒有“唯一標識”,這樣說可能有點簡單,????

聚合和聚合根

上面給出的例子中:

  • 房子、訂單和問題是聚合根
  • 窗戶、訂單備註和問題詳情是聚合

當數據改變時,所有相關的對象被看作一個整體。

所有的外部數據訪問都需要通過同一個根節點進入,這個根就是根節點

領域驅動設計(DDD)- 請先搞清楚一些概念