官术网_书友最值得收藏!

總覽

從廣義上講,領域(Domain)即是一個組織所做的事情以及其中所包含的一切。商業(yè)機構通常會確定一個市場,然后在這個市場中銷售產品和服務。每個組織都有它自己的業(yè)務范圍和做事方式。這個業(yè)務范圍以及在其中所進行的活動便是領域。當你為某個組織開發(fā)軟件時,你面對的便是這個組織的領域。這個領域對于你來說應該是明晰的,因為你在這個領域中工作。

有一點需要注意的是,“領域”這個詞可能承載了太多含義。領域既可以表示整個業(yè)務系統(tǒng),也可以表示其中的某個核心域或者支撐子域。在本書中,我將盡可能地區(qū)分這些概念。當談及到業(yè)務系統(tǒng)中的某個方面時,我會使用諸如“核心域”或者“子域”以示區(qū)別。

由于“領域模型”包含了“領域”這個詞,我們可能會認為應該為整個業(yè)務系統(tǒng)創(chuàng)建一個單一的、內聚的、全功能式的模型。然而,這并不是我們使用DDD的目標。正好相反,在DDD中,一個領域被分為若干子域,領域模型在限界上下文中完成開發(fā)。事實上,在開發(fā)一個領域模型時,我們關注的通常只是這個業(yè)務系統(tǒng)的某個方面。試圖創(chuàng)建一個全功能的領域模型是非常困難的,并且很容易導致失敗。就像本章中所講到的一樣,對領域的拆分將有助于我們成功。

那么,既然領域模型不能包含整個業(yè)務系統(tǒng),我們應該如何來劃分領域模型呢?

幾乎所有軟件的領域都包含多個子域,這和軟件系統(tǒng)本身的復雜性沒有太大關系。有時,一個業(yè)務系統(tǒng)的成功取決于它所提供的多種功能,而將這些功能分開對待是有好處的。

工作中的子域和限界上下文

對于如何使用子域,讓我們先來看一個非常簡單的例子——一個零售商在線銷售產品的例子。要在這個領域中開展業(yè)務,該零售商必須向買家展示不同類別的產品,允許買家下單和付款,還需要安排物流。在這個領域中,零售商的領域可以分為4個主要的子域:產品目錄(Product Catalog)、訂單(Order)、發(fā)票(Invoicing)和物流(Shipping)。圖2.1的上半部分表示了這樣一個電子商務系統(tǒng)。

這看來是非常簡單的,但是,如果我們再向其中加入一個額外的細節(jié),以上這個例子將變得復雜起來。思考一下,如果我們向以上的電子商務系統(tǒng)中再加入一個庫存(Inventory)系統(tǒng),如圖2.1所示,情況會變得如何?接下來,讓我們來看看圖2.1所展示的物理子系統(tǒng)和邏輯子域。

該零售商的領域中只包含了三個物理系統(tǒng),其中有兩個是內部系統(tǒng)。這兩個內部系統(tǒng)表示兩個限界上下文。不幸的是,由于現(xiàn)在多數(shù)軟件系統(tǒng)并沒有采用DDD,這導致了少數(shù)的幾個子系統(tǒng)承擔了太多的業(yè)務功能。

img

圖2.1 一個含有子域和限界上下文的領域

在上面的電子商務限界上下文中,我們的確可以找出多個隱式的領域模型,即便它們并沒有被很好地分離出來。事實上,這些領域模型被融合成了一個軟件模型,這是不幸的。對于該零售商來說,與其自己開發(fā),還不如從第三方購買這么一個限界上下文,因為這樣所帶來的問題可能會少一些。然而,不管是誰來維護這個系統(tǒng),它都將承受這個大而全的電子商務模型所帶來的負面影響。隨著各個邏輯模型中不斷加入新的功能,它們之間的復雜關系對于每一個模型都將是阻礙,特別是需要引入另外一個邏輯模型的時候。這些問題的原因通常都是由于軟件的關注點沒有得到清晰的劃分所致。

更不幸的是,很多軟件開發(fā)者都認為將所有東西都放在一個系統(tǒng)里面是一件好事。他們會想:“我對電子商務系統(tǒng)了如指掌,我相信這個系統(tǒng)可以滿足任何人的需求?!边@是具有欺騙性的,因為不管你向系統(tǒng)中添加多少功能,你都無法滿足每一個潛在客戶的需求。此外,如果不通過子域對軟件模型進行劃分,事情將變得更加煩瑣,因為系統(tǒng)中的各個部分都是緊密聯(lián)系在一起的。

然而,通過使用DDD戰(zhàn)略設計工具,我們可以按照實際功能將這些交織的模型劃分成邏輯上相互分離的子域,從而在一定程度上減少系統(tǒng)的復雜性。邏輯子域的邊界在圖2.1中以虛線表示。這里,我們將第三方的模型也做了清晰地劃分,但這不是我們的重點,我們的重點在于說明應該存在什么樣的分離模型。在不同的邏輯子域之間或者不同的物理限界上下文之間均畫有連線,這表示它們之間存在集成關系。

現(xiàn)在,讓我們將視線從技術復雜性轉向這個零售商的業(yè)務復雜性。該零售商的資金和倉庫容量均有限。對于那些銷量不佳的產品,該零售商不敢過量投入。顯然,如果有產品沒有按照計劃銷售出去,那么該零售商的流動資金將出現(xiàn)問題。因此,它只能用有限的房間來存儲那些銷量好的產品。

這還沒完,還有另外一個問題。如果有些產品銷量好于預期,那么該零售商便沒有足夠的庫存,此時顧客將不得不到別處購買商品。當然,有些產品生產商會自己負責產品的物流,但是這樣對于零售商來說成本更大,并且會帶來一些不良后果。另一種節(jié)約成本的做法是,對于本地售出產品采用自留庫存,而對于偏遠地區(qū)則采用生產商直接發(fā)貨的方式。這樣,該零售商便不至于在庫存清空時捉襟見肘了。事實上,導致庫存清空的原因并不是產品銷售得異常好,而是該零售商沒有找到一種最優(yōu)的庫存管理方式。如果經常發(fā)生產品不能及時送達客戶的情況,那么該零售商將損失很大一部分競爭優(yōu)勢。

庫存問題不僅是小型零售商的問題,大型零售商同樣面臨這樣的問題。各個零售商家都根據(jù)準確的需求來囤積產品,從而減少成本,優(yōu)化銷售業(yè)務。但是,在庫存問題面前,小型零售商比大型零售商更加脆弱。

一種好的做法是,根據(jù)過去的銷售趨勢來制定未來的庫存計劃。零售商可以采用一個預測引擎,根據(jù)庫存和銷售歷史來分析產品的需求量,從而達到優(yōu)化庫存系統(tǒng)的目的。

對于小型零售商來說,增加預測引擎可能意味著開發(fā)一個新的核心域,這并不是一個容易解決的問題,但是可以大大增加競爭優(yōu)勢。事實上,圖2.1中的第三個限界上下文便是一個外部預測系統(tǒng)。訂單子域和庫存限界上下文向預測系統(tǒng)提供歷史銷售數(shù)據(jù)。此外,我們還需要產品目錄子域來提供全局的產品條形碼,這將有助于預測系統(tǒng)在全球范圍之內對產品的銷售情況進行比較。這樣一來,預測系統(tǒng)便可以精確地計算出產品的需求量,并指導零售商制定正確的庫存計劃。

如果這個新的解決方案是一個核心域,那么開發(fā)團隊將從周圍的邏輯子域以及集成體系中受益。因此,在該核心域的項目啟動時,圖2.1中已有的集成體系對于掌握項目情況來說將起到關鍵作用。

子域并不是一定要做得很大,并且包含很多功能。有時,子域可以簡單到只包含一套算法,這套算法可能對于業(yè)務系統(tǒng)來說非常重要,但是并不包含在核心域之中。在正確實施DDD的情況下,這種簡單的子域可以以模塊(Module,9)的形式從核心域中分離出來,而不需要包含在笨重的子系統(tǒng)組件中。

在實施DDD的時候,我們致力于將限界上下文中領域模型所用到的每一個術語都進行限界劃分。這種限界主要是語言層面上的上下文邊界,也是實現(xiàn)DDD的關鍵。

牛仔的邏輯

LB:“有護欄相隔時,我和鄰居相處得很好,護欄壞了之后,情況就變了?!?/p>

AJ:“對的,你需要將你的護欄造成和馬一樣高。”

需要注意的是,一個限界上下文并不一定只包含在一個子域中,但這是可能的。在圖2.1中,只有庫存限界上下文包含在了一個子域中。顯然,這表明這個電子商務系統(tǒng)在開發(fā)的時候并沒有正確地采用DDD。在這個系統(tǒng)中,我們識別出了4個子域,然而還可能有更多的子域。另一方面,庫存系統(tǒng)看起來的確符合“一個子域對應一個限界上下文”的標準。庫存系統(tǒng)這種清晰的模型有可能是采用了DDD的結果,也有可能是種偶然,對此我們需要深入地研究。但無論如何,我們都可以使用這個庫存系統(tǒng)來開發(fā)新的核心域。

在圖2.1中,哪種類型的限界上下文在語言表達層面上設計得更好呢?換句話說,哪種限界上下文擁有非歧義的領域特定術語?在上面的電子商務系統(tǒng)中,當我們談到其中有4個子域時,我們可以非常確定地認為有些術語在這些子域中是存在沖突的。比如,“顧客”這個術語可能有多種含義。在瀏覽產品目錄的時候,“顧客”表示一種意思;而在下單的時候,“顧客”又表示另一種意思。原因在于:當瀏覽產品目錄時,“顧客”被放在了先前購買情況、忠誠度、可買產品、折扣和物流方式這樣的上下文中。而在下單時,“顧客”的上下文包括名字、產品寄送地址、訂單總價和一些付款術語。單單從這個例子我們便可以看出,在這個電子商務系統(tǒng)中,“顧客”并沒有一個清晰的含義。我們甚至還可以找到很多像“顧客”這樣擁有多重含義的術語。在一個好的限界上下文中,每一個術語應該僅表示一種領域概念。

然而,我們同樣不能保證庫存系統(tǒng)的模型就是完全清晰的,并且使用了完全非歧義的領域語言。即使是在關注點分離明顯的限界上下文中,也會存在和上面的“顧客”相似的情況,因為庫存件可能用在不同的環(huán)境下。比如,有的庫存件已經被訂購了,有的正在運送途中,有的正保存在倉庫中,而有的正被移出倉庫。已經被訂購但還無法銷售的產品稱為延期訂單件;保存在倉庫中的產品稱為積壓件;剛被購買的產品稱為即將發(fā)送件;而被損壞的庫存產品稱為無用件。

在圖2.1中,我們看不出以上這些庫存概念。在DDD中,我們不能靠猜測,而應該對每個概念都給出明確的定義,并將這些明確的定義用在交流和建模中。領域專家對這些概念的解釋有助于在不同的限界上下文中分離這些概念。

從表面看來,我們可以得出結論:庫存系統(tǒng)比電子商務系統(tǒng)具有更高的DDD健康指數(shù),原因可能是庫存系統(tǒng)的開發(fā)團隊并沒有使用一個庫存件來表示所有的概念。雖然目前我們還不明確這一點,但是我們可以肯定的是:庫存系統(tǒng)模型比電子商務系統(tǒng)模型更容易集成。

圖2.1進一步表明,一個企業(yè)的限界上下文并不是孤立存在的。即便有第三方的電子商務系統(tǒng)可以提供一個全方位式的模型,它也不能完全滿足零售商的需求。不同子域之間的實線表示集成關系,這也表明不同的模型是需要協(xié)同工作的。集成的方式有很多種,我們將在上下文映射圖(3)中學到不同的集成方案。

以上,我們在一個高層面上對一個簡單的業(yè)務領域進行了總結。我們簡要地學習了一個核心域,并且了解了核心域對于DDD的重要性。接下來,我們需要深入學習核心域。

將關注點放在核心域上

了解了子域和限界上下文,現(xiàn)在我們來看看關于領域的另一個抽象視圖,如圖2.2所示。該抽象視圖可以表示任何一個領域,甚至有可能是你正在工作的領域。和圖2.1相比,我去除了那些具體的名字,你可以根據(jù)自己的項目情況進行填補。我們會持續(xù)改進并且擴大業(yè)務目標,這將反映在不斷變化的子域和子域模型中。圖2.2僅僅表示某個時刻,從某個角度看的業(yè)務領域,這樣的領域可能并不會駐留多久。

img

圖2.2 一個抽象的業(yè)務領域,其中包含了子域和限界上下文

白板時間

? 在一欄中列出你日常工作中的子域,然后在另一欄中列出限界上下文。子域和限界上下文有相交的地方嗎?如果有,這并不是什么壞事,因為這正是企業(yè)級軟件的本來面目。

? 以圖2.2為模板,根據(jù)你自己的軟件項目填入相應的名字,包括子域、限界上下文和集成關系。

這困難嗎?有可能,因為圖2.2中的模板可能并沒有反映出你工作領域的邊界。

? 再來一次,畫出能表示你的領域、子域和限界上下文的框圖。你可以參考圖2.2,但是所畫框圖應該表示你自己的領域。

當然,你不用了解所有的子域和限界上下文,特別是當你的領域非常復雜的時候。但是,你可以將那些你每天都會接觸到的子域和限界上下文識別出來。不管怎樣,先試試再說,不要害怕犯錯誤。你會在下一章的上下文映射圖中學到好的實踐方法,如果你想現(xiàn)在就跳到下一章去也是可以的??傊?,不要擔心現(xiàn)在還不完美,我們首先需要了解基本概念。

現(xiàn)在,看看圖2.2上半部分的領域邊界,你會看到一個叫核心域的子域。對于核心域,我們在前面的章節(jié)中已經講到了,它是整個業(yè)務領域的一部分,也是業(yè)務成功的主要促成因素。從戰(zhàn)略層面上講,企業(yè)應該在核心域上勝人一籌。我們應該給予核心域最高的優(yōu)先級、最資深的領域專家和最優(yōu)秀的開發(fā)團隊。在實施DDD的過程中,你將主要關注于核心域。

圖2.2中還展示了另外兩種子域:支撐子域和通用子域。有時,我們會創(chuàng)建或者購買某個限界上下文來支撐我們的業(yè)務。如果這樣的限界上下文對應著業(yè)務的某些重要方面,但卻不是核心,那么它便是一個支撐子域。創(chuàng)建支撐子域的原因在于它們專注于業(yè)務的某個方面,否則,如果一個子域被用于整個業(yè)務系統(tǒng),那么這個子域便是通用子域。我們并不能說支撐子域和通用子域是不重要的,它們是重要的,只是我們對它們的要求并不像核心域那么高。

白板時間

? 為了鞏固你對核心域概念的掌握,你可以溫習一遍先前所繪的框圖,看看自己能否識別出核心域。

? 接下來,看看自己能否識別出支撐子域和通用子域。

記住:向領域專家提問!

即便在開始時你會犯下錯誤,但這種練習可以幫助你仔細地思考哪些是最重要的,哪些是起輔助作用的,哪些是無關緊要的。

對于你所繪框圖中的子域和限界上下文,你需要和領域專家進行討論。

你不但可以從領域專家那里學到很多,同時你還能學到聆聽的技巧,這也是正確實施DDD的標志。

到此,我們總覽式地學習了DDD戰(zhàn)略設計的基礎。

主站蜘蛛池模板: 张北县| 甘肃省| 永昌县| 买车| 砀山县| 高阳县| 景德镇市| 佛冈县| 刚察县| 安阳市| 育儿| 湘潭市| 武城县| 昌图县| 潞西市| 青神县| 汝城县| 洛阳市| 韶山市| 文登市| 嵊州市| 兴和县| 忻城县| 英山县| 泗阳县| 沂源县| 永昌县| 额敏县| 麦盖提县| 遵义县| 临西县| 麻栗坡县| 柘城县| 河间市| 海兴县| 灌阳县| 罗甸县| 朝阳县| 句容市| 马公市| 宜阳县|