領域驅動設計(DDD)部分核心概念
領域驅動設計(DDD)是一種基於模型驅動的軟件設計方式。它以領域爲核心,分析領域中的問題,通過建立一個領域模型來有效的解決領域中的核心的複雜問題。Eric Ivans 爲領域驅動設計提出了大量的最佳實踐和經驗技巧。只有對領域的不斷深入認識,才能得到一個解決領域核心問題的領域模型。如果一個應用的複雜性不是在技術方面的,而是在領域本身,即領域內的業務很複雜,那這種應用,使用領域驅動設計的價值就越大。
領域驅動開發也是一種敏捷開發過程(極限編程,XP),強調迭代開發。在迭代過程中,強調開發人員與領域專家需要保持密切的合作關係。極限編程假設我們能通過不斷快速重構完善設計。所以,對開發人員的要求非常高。
領域驅動設計提出了一套核心構造塊(Building Blocks,如聚合、實體、值對象、領域服務、領域工廠、倉儲、領域事件,等), 這些構造塊是對面向對象領域建模的一些核心最佳實踐的濃縮。這些構造塊可以使得我們的設計更加標準、有序。
統一語言(Ubiquitous Language),是領域驅動設計中一個非常重要的概念。任何一個領域驅動設計的項目,都需要一種通用語言,一套通用的詞彙。因爲沒有通用的語言,就沒有一致的概念,溝通就會遇到障礙,最後的領域模型和軟件也就無法滿足領域內的真實業務需求。通用語言是領域專家和開發人員在對領域問題的溝通、需求的討論、開發計劃的制定、領域模型的設計,以及開發人員之間對領域模型的具體編碼落地實現,等一系列過程中,所有人員使用的一種通用語言。換句話說,就是無論是溝通時所用的詞彙、還是領域模型中的概念、還是代碼中出現的類名與方法,只要是相同的意思,那就應該使用相同的詞彙。可以看出,這種通用語言不是一下子就可以形成,而是在一個各方人員討論的過程中,不斷髮現、明確,與精煉出來的。
領域模型是領域驅動設計的核心。統一語言中的所有關鍵詞彙,在領域模型上應該都能找到。各方人員溝通時,都應該以領域模型爲基礎。通過討論的不斷深入,大家對領域的認識也會不斷深入,領域模型也會不斷得到完善,統一語言的詞彙也會不斷豐富和精準。需要特別強調的是,開發人員應該儘量保證代碼實現和領域模型相綁定,時刻保持代碼與模型的一致。如果不綁定,那代碼就會慢慢和模型相脫節,就會出現像我們以前那樣的設計文檔和代碼相脫節一樣的問題,甚至模型還會起到誤導作用。通過這樣一種思路,我們確保語言、模型、代碼三者緊密綁定,確保最後實現出來的軟件可以準確無誤的實現業務需求,並且還能讓我們的軟件可以快速的和業務同時演進。而不像傳統的開發方式那樣,分析、設計、實現三個階段完全脫節,最後出來的軟件沒有很好的滿足業務需求,也不能在未來很快的跟業務需求一起演進。所以,領域模型同時承載了分析的結果和設計的結果,這裏的分析是指對領域內業務需求的分析,設計是指對模型的設計以及軟件的設計。所以,我們的領域模型,不能只考慮業務需求,還要同時考慮軟件設計的原則,是一種綜合考慮的、平衡的設計結果。
領域模型可以複用,因爲特定的領域模型解決的都是某個特定的問題域;比如淘寶網有個商品中心,有個商品模型,核心概念有商品分類、商品;商品模型負責解決電子商務領域中的商品目錄(Product Catalog)子域。後來阿里又出了個天貓,也會有商品中心,但是這兩個商品中心基本是一樣的問題域。所以,我們可以複用之前淘寶實現的商品中心領域模型,並複用之前淘寶商品中心的解決方案,來解決天貓的商品維護和展示。當然,這個只是我個人的認識,一個例子。具體阿里是否是一個商品中心同時解決淘寶和天貓的業務,沒具體調研過。
Bounded Context,屬於一種軟件構件,作用是用來對領域模型進行劃分。Bounded Context 有兩層含義:
Bounded,即有邊界的,表示領域模型有邊界;這個邊界定義了模型的適用範圍,以便讓負責該模型的團隊知道什麼該在模型中實現,什麼不該;
Context,即領域模型的產生是在某個上下文中產生的;上下文是一個和環境相關的概念。比如一次頭腦風暴會議大家達成了一個模型,那這次會議的討論就是該模型的上下文;比如某本書中談到了某個東西,那這個東西的上下文就是那本書,那個東西要有意義的前提離不開那本書這個上下文;所以,上下文是模型有意義的前提;
領域建模的方法有很多種,大概的思路是:
通過與領域專家和業務需求人員溝通,找出領域中的關鍵業務場景;
針對每個業務場景分析出有哪些場景參與者,哪些參與者以對象(聚合)的形式參與,哪些參與者以服務的形式參與;
分析每個場景參與者對象的基本狀態特徵;
分析每個場景參與者對象分別扮演什麼角色參與場景,整個場景的完整交互過程是怎樣的,對象在參與場景的過程中執行了哪些交互行爲;
分析如何記錄和跟蹤這一次交互行爲,分析這次交互行爲會產生哪些額外的信息;
關於領域(Domain)、領域模型(Domain Model)、邊界上下文(Bounded Context)的關係
領域就是問題域,問題空間;
領域模型是一種模型,表達了領域中那些業務需求以及業務規則必須被滿足;
每一個領域中的問題,都會有一個對應的領域模型去解決;
Bounded Context 的作用是用來對領域模型進行劃分;
劃分領域就是對問題空間的劃分,通俗的理解,就是將大問題拆分爲小問題;
劃分 Bounded Context 就是將一個大的領域模型劃分爲多個小的領域模型;
可以把 Bounded Context 看成是一種解決方案空間,所以,Bounded Context 也可以理解爲是對解決方案空間的劃分;
理論上,一個 Domain 可能會對應多個 Bounded Context;同樣,一個 Bounded Context 可能也會對應多個 Domain;所以他們之間沒有絕對的關係。主要是他們劃分的依據不同,一個是針對領域(問題空間),一個是針對領域模型(解決方案空間);理想情況,一個 Domain 最好對應一個 Bounded Context;
關於 Domain、Sub Domain、Core Domain、Generic Domain,以及 Shared Kernal 的理解:
一個領域(Domain)會拆分爲多個子領域(Sub Domain);
子領域中最核心(最重要)的那個叫 Core Domain;我們應該將團隊的核心資源用在覈心子域上,因爲它是產品成敗的關鍵;
除了 Core Domain 外,其他的是支撐子域(Supporting Subdomain);
有些支撐子域比較特殊,因爲它解決的是一類通用問題,比如賬號和權限;這類子域我們叫做通用子域(Generic Subdomain);通常,通用子域對應的 Bounded Context,會跨域多個子域;
多個子領域有時會有相交的部分,我們稱作共享內核(Shared Kernel);體現到代碼上,就是同一份代碼,在兩個領域模型中複用;
一般只有 Domain 比較大的時候,我們纔會劃分出 Sub Domain;
爲什麼一個大的領域模型需要劃分?因爲,通常一個大的領域模型需要多個團隊合作完成。如果多個團隊基於一個共同的領域模型工作,由於每個團隊的關注點不同,且一些看似叫法一樣的概念,對於不同的團隊,其背後的意思完全不同。所以,這樣的概念含義模糊會給團隊以及成員之間的合作帶來很大的困擾。所以,我們需要通過一種手段(Bounded Context),將領域模型劃分爲不同的部分,確保同一個 Bounded Context 內的領域模型所表達的概念含義明確。然後,同一個 Bounded Context 下面,相關人員都使用一種統一的語言,以此來保證團隊成員之間溝通能暢通無阻。
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/CFdkqhJVdXkmOvSq5t0ycA