DDD(領域驅動設計)–戰略設計

實現領域驅動設計

領域

領域是一個組織所做的事情以及其中所包含的一切。商業機構通常會確定一個市場,然後在這個市場中銷售產品和服務。每個組織都有它自己的業務範圍和做事方式。
領域就是解決一個特定範圍內的業務問題。

如何分析領域

在研究與建模的過程中,開發人員是不能孤軍奮戰的,這個時候需要找領域專家一起建模,領域專家是精通業務的任何人,他們可能是軟件產品的設計者,甚至有可能是銷售。
領域專家把他的知識傳給開發者,讓建模更符合實際業務情況,以此也能獲得更好的用戶體驗。

子域

分而治之,DDD是一套處理複雜領域的設計方法。
當我們遇到一個複雜的問題時,通常的做法就是將問題一步一步地細化,再針對細化出來的問題域逐個深入研究。當所有的子問題都完成研究時,我們也就建立了全部領域的完整知識。
子域是整個業務領域的一部分,大多數的業務領域都過於龐大和複雜,難以作為整體來分析,因此需要對整個業務領域進行拆分。

子域劃分

  • 核心域:它是一個定義明確的領域模型,需要投入大量資源去精心打磨的子域。它是組織中最重要的模塊,因為這將是和其他競爭者的區別所在,需要把這個核心域打造成為組織的核心競爭力。
  • 支撐域:這類子域,可能找不到現成的解決方案,對它的投入如何也達不到與核心域相同的程度。但核心域的成功離不開支撐域。這個子域不需要過度地考慮可擴展性和兼容性,如果要考慮的,應該是可替代性。這也就要求支撐子域需要有明確的契約規範和業務約束條件。這種子域一般提倡「定製開發」。
  • 通用域:通用子域內的業務規則相對明確,一般解決方案可以通過採購獲取,對其定製化要求比較低,而穩定性和兼容性則要求較高。

現實世界中領域與子域

領域中還同時存在問題空間和解決空間。在問題空間中,我們思考的是業務所面臨的挑戰,而在解決方案空間中,我們思考如何實現軟件以解決這些業務挑戰。
問題空間與解決空間

通用語言(Ubiquitous Language)

日常開發過程中,大家應該都有這種感受,在和產品經理、運營等交流過程中,經常會有各種扯皮,沒法溝通的時候,很大一部分原因就是大家溝通的時候,用詞含義不一致導致的。
要想創建一種靈活的、蘊含豐富知識的設計,需要一種通用的、共享的團隊語言。如果語言支離破碎,項目必將受阻,實現過程中可能得不到符合要求的產品。
所以我們需要有一套通用語言,領域專家、產品、開發、運營等通用的語言,需要包括類和主要操作的名稱。並將這些通用語言應用到需求討論、技術方案設計、圖和代碼中。

限界上下文(Bounded Context)

生物學中,我們知道,細胞之所以能夠存在,是因為細胞膜限定了什麼在細胞內,什麼在細胞外,並且確定了什麼物質可以通過細胞膜。
軟件系統中也是一樣,我們需要有一個限界上下文,明確地定義模型所應用的上下文,根據團隊的組織,軟件系統的各個部分的用法以及物理表現(代碼合數據庫模式)來設置模型的邊界。在這些邊界中嚴格保持模型的一致性,而不要受到邊界之外問題的干擾和混淆。

限界上下文是一個顯式的邊界,領域模型變存在於這個邊界之內。每一個模型概念,包括它的屬性和操作,在邊界之內都具有特殊的含義。

在現實世界中,領域的邊界很模糊,但是要設計一個好的解決方案,我們需要對問題子域加上一個邊界,將不重要的信息排除在邊界外。讓解決方案專心解決重點問題。

每個上下文都代表着該解決方案的專業知識。在同一個上下文里,我們共享統一的語言和一致的設計。
通過界限上下文人為將問題子域限制在有限的界限內,你才可以着手創建解決方案。

上下文映射(Context Mapping)

每個限界上下文不可能獨立存在,基本都需要與其他上下文進行集成,上下文映射是為了用來描述限界上下文之間的協作問題。這種集成關係在DDD中成為上下文映射,有如下幾種映射方式。

Context Mapping

合作關係(Partnership):如果兩個限界上下文的團隊要麼一起成功,要麼一起失敗,要麼一起成功,此時他們需要建立起一種合作關係。合作越多依賴越多,耦合越嚴重,甚至出現雙向依賴。

共享內核(Shared Kernel):當不同團隊開發一些緊密相關的應用時,如果團隊直接不進行協調,即使短時間能夠取得快速進展,但他們開發出來的產品可能無法結合到一起。最後可能不得不耗費大量精力在轉換層上,並且頻繁地進行改動,不如一開始就從領域模型中選出兩個團隊都同意共享的一個子集,減少重複的工作。這種模式下,在沒有與另一個團隊協商的情況下,這種狀態是不可改變的,同時需要引入一種持續集成過程來保證共享內核與通用語言的一致性。

客戶方-供應方開發(Customer-Supplier Development):正常情況下,這是團隊合作中最為常見的合作模式。當兩個團隊處於一種上游-下游關係時,上游團隊可能獨立於下游團隊完成開發,此時下游團隊的開發可能會受到很大的影響。因此,在上游團隊的計劃中,我們應該顧及到下游團隊的需求。

遵奉者/追隨者(Confoemist):下游團隊直接使用上游團隊的模型,簡化集成。

防腐層(Anticorruption Layer):防腐層通過已有的接口與其他系統交互,而其他系統只需要做很小的修改,甚至無須修改。在防腐層內部,它在你自己的模型和他方模型之間翻譯轉換。

開放主機服務(Open Host Service):定義一種協議,讓你的子系統通過該協議來訪問你的服務。你需要講該協議公開,這樣任何想與你集成的人都可以使用該協議。

發佈語言(Published Language):在兩個限界上下文之間翻譯模型需要一種公用的語言。此時你應該使用一種發佈出來的共享語言來完成集成交流。發佈語言通常與開放主機服務一起使用。

另謀他路/各行其道(SpeparateWay):在確定需求時,我們應該做到堅決徹底。如果兩套功能沒有顯著的關係,那麼它們是可以被完全解耦的。集成總是昂貴的,有時帶給你的好處也不大。聲明兩個限界上下文之間不存在任何關係,這樣使得開發者去另外尋找簡單的、專門的方法來解決問題。

大泥球(Big Ball of Mud):當我們檢查已有系統時,經常會發現系統中存在混雜在一起的模型,它們之間的邊界是非常模糊的。此時你應該為整個系統繪製一個邊界,然後將其歸納在大泥球範圍之列。在這個邊界之內,不要嘗試使用複雜的建模手段來化解問題。同時,這樣的系統有可能會向其他系統蔓延,你應該對此保持警覺。

參考資料

Tags: