一、概述
? ? ? ? 隨著系統的增長,它會越來越復雜,當我們無法通過分析對象來理解系統的時候,就需要掌握一些操縱和理解大模型的技術了。
? ? ? ? 最負雄心的企業欲實現一個涵蓋所有業務、緊密集成的系統。因大型公司的業務模型巨大且復雜,很難把它作為一個整體來理解且難以管理。按傳統做法,我們可以將其拆為較小的部分后組合。但問題在于,如何保證實現這種模塊化的同時,不失去集成所具備的好處;從而使系統的不同部分能夠進行互操作,以便協調各種業務操作。如果設計一個把所有概念都涵蓋進來的單一領域模型,它將會非常笨拙,而且將會出現大量難以察覺的重復和矛盾。而如果用臨時拼湊的接口把一組小的、各自不同的子系統集成到一起,又不具備解決企業級問題的能力,并且在每個集成點上都有可能出現不一致。通過采用系統的、不斷演變的設計策略,就可以避免這兩種極端問題。
? ? ? ? 即使這種規模的系統中采用領域驅動設計方法,也不要脫離實現去開發模型。每個決策都必須對系統開發產生直接的影響,否則它就是無關的決策。戰略設計原則必須指導設計決策,以便減少各個部分之間的互相依賴,在使設計意圖更為清晰的同時而不失去關鍵的互操作性和協同性。戰略設計原則必須把模型的重點放在捕獲系統的概念核心,也就是系統的“遠景”上。而且在完成這些目標的同時又不能為項目帶來麻煩。為了幫助實現這些目標,需探索三個主題:上下文、精煉和大型結構。
? ? ? ? 1、上下文是最不易引起注意的原則,但實際上它卻是最根本的。無論大小,成功的模型必須在邏輯上一致,不能有互相矛盾或重疊的定義。有時,企業系統會集成各種不同來源的子系統,或包含諸多完全不同的應用程序,以至于無法從同一個角度來看待領域。要把這些不同部分中隱含的模型統一起來可能是要求過高了。通過為每個模型顯式地定義一個Bounded Context,然后在必要的情況下定義它與其他上下文的關聯,建模人員就可以避免模型變得纏雜不清。
? ? ? ? 2、精煉可以減少混亂,并且把注意力集中到正確的地方。人們通常在領域的一些次要問題上花費太多的精力。整體領域模型需要突出系統中最有價值和最特殊的那些方面,而且在構造領域模型時應該盡可能把注意力集中在這些部分上。雖然一些支持組件也很關鍵,但絕不能把它們和領域核心一視同仁。把注意力集中到正確的地方不僅有助于把精力投入到關鍵部分上,而且還可以使系統不會偏離預期方向。戰略精煉可以使大的模型保持清晰。有了更清晰的視圖后,Core Domain的設計就會發揮更大的作用。
? ? ? ? 3、大型結構是用來描述整個系統的。在非常復雜的模型中,人們可能會“只見樹木,不見森林”。精煉確實有幫助,它使人們能夠把注意力集中到核心元素上,并把其他元素表示為支持作用,但如果不貫徹某個主旨來應用一些系統級的設計元素和模式的話,關系仍可能非常混亂。有幾種組織大型結構的方法,可以用它們作為基礎結構,去構建我們需要的大型結構。如Responsibility Layer(職責層) 、Evolving Order等。
? ? ? ? 這3種原則各有各的用處,但結合起來使用將發揮更大的力量。大型結構和精煉能夠幫助我們理解各個部分之間的復雜關系,同時保持整體視圖的清晰。Bounded Context(上下文)能夠使我們在不同的部分中進行工作,而不會破壞模型或是無意間導致模型的分裂。把這些概念加進團隊的Ubiquitous Language中,可以幫助開發人員找出大型模型的自己的解決方案。
二、保持模型的完整性
? ? ? ? 模型最基本的要求是它應該操持一致,術語總是具有相同的意義,并且不包含互相矛盾的規則:雖然我們很少明確地考慮這些要求。模型內部的一致性又叫統一(Unification),這種情況下,每個術語都不會有模棱兩可的意義,也不會有規則沖突。
? ? ? ? 但大型系統開發并非如此理想。在整個企業系統中保持這種水平的統一是一件得不償失的事情。在系統的各個不同部分中開發多個模型是很有必要的,但我們必須慎重地選擇系統的哪些部分可以分開,以及它們之間是什么關系。我們需要是一些方法來保持模型關鍵部分的高度統一。這需要通過有意識的設計決策和建立特定過程才能實現。大型系統領域模型的完全統一即不可行,也不劃算。
? ? ? ? 有時人們會反對這一點,多個模型看上去似乎不夠雅致。甚至對多個模型的抵觸會導致“極富雄心”的嘗試——將一個大型項目的所有軟件統一到單一模型中。如果想這樣做一定要考慮以下風險。
? ? ? ? (1)一次嘗試對遺留系統做過多的替換。
? ? ? ? (2)大項目可能會陷入困難,因為協調的開銷太大,超出了這些項目的能力范圍。
? ? ? ? (3)具有特殊需要的應用程序可能不得不使用無法充分滿足需要的模型,而只能將這些無法滿足的行為入到其他地方。
? ? ? ? (4)另一方面,試圖用一個模型來滿足所有人的需求可能會導致模型中包含過于復雜的選擇,因而很難使用。
? ? ? ? 此外,除了技術的因素外,權力上的劃分和管理級別的不同也可能要求把模型分開。而且不同模型的出現也可能是團隊組織和開發過程導致的結果。因此,即使完全的集成沒有來自技術方面的阻力,項目也可能面臨多個模型。
? ? ? ? 既然無維護一個涵蓋整個企業的統一模型,那就不要再受到這種思路的限制。通過預先決定什么應該統一,并實際認識到什么不能統一,我們就能夠創建一個清晰的、共同的視圖。確定了這些之后,就可以開始著手開始工作,以保證那些需要統一的部分保持一致,不需要統一的部分不會引起混亂或破壞模型。
? ? ? ? 我們需要用一種方式來標記出不同模型之間的邊界和關系。我們需要有意識地選擇一種策略,并一致地遵守它。
? ? ? ? 為識別、溝通和選擇模型邊界及關系,我們使用了一些模式,Bounded Context(限界上下文)定義了每個模型的應用范圍,而Context Map(上下文圖)則給出了項目上下文以及它們之間關系的總體視圖。這些降低模糊性的技術能夠使項目更好地進行,但還不夠。一旦確立了Context的邊界之后,仍需要持續集成這種過程,它能夠使模型保持統一。
? ? ? ? 其后,在這個穩定的基礎之上,我們就可以開始實施那些在界定和關聯Context方面更有效的策略——從通過共享內核(Shared Kernel)來緊密上下文,到那些各行其道(Separate Ways)地進行松散耦合的模型。
? ? ? ? 模型完整性模式的導航圖?
1、模式:Bounded Context
? ? ? ? 大型項目上會有多個模型共存,在很多情況下這沒什么問題。不同的模式應用于不同的上下文中。但也會有引起含糊和混亂的情況。如:兩個團隊為同一個新系統開發不同的功能,那么他們使用的是同一個模型嗎?他們的意圖是至少共享其所做的一部分工作,但卻沒有界限告訴他們共享什么、沒共享什么。而且他們也沒有一個過程來維護共享模型,或快速檢測模型是否有分歧。他們只是在系統行為不可預測時才意識到他們之間產生了分歧。
? ? ? ? 即使在同一個團隊中,也可能會出現多個模型。團隊的溝通可能會不暢,導致對模型的理解產生難以捉摸的沖突。原先的代碼往往反映的是早先的模型概念,而這些概念與當前模型有著微妙的差別。
? ? ? ? 每個人都知道兩個系統的數據格式是不同的,因此需要進行數據轉換,但這只是問題的表面。問題的根本在于兩個系統所使用的模型不同。當這種新差異不是來自外部系統,而是發生在同一個系統中時,它將更難發現。然而,所有大型團隊項目都會發生這咱情況。
? ? ? ? 任何大項目都會存在多個模型。而當基于不同模型的代碼被組合到一起后,軟件就會出現Bug、變得不可靠和難以理解。團隊成員之間的溝通變得混亂。人們往往弄不清楚一個模型不應該在哪個上下文中使用。
? ? ? ? 模型混亂的問題最終會在代碼不能正常運行時暴露出來,但問題的根源卻在于團隊的組織方式和成員的交流方法。因此,為了澄清模型的上下文,我們既要注意項目,也要注意它的最終產品(代碼、數據庫模式等)。
? ? ? ? 一個模型只在一個上下文中使用。這個上下文可以是代碼的一個特定部分,也可以是某個特定團隊的工作。如果模型是在一次頭腦風暴會議中得到的,那么這個模型的上下文可能僅限于那次討論。就拿本書來說,示例中所使用的模型的上下文就是那個示例所在的小節以及任何相關的后續討論。模型上下文是為了保證該模型中的術語具有特定意義而必須要應用的一組條件。
? ? ? ? 為了解決多個模型的問題,我們需要明確地定義模型的范圍——模型的范圍是軟件系統中一個有界的部分,這部分只應用一個模型,并盡可能保持統一。團隊組織必須一致遵守這個定義。
? ? ? ? 因此:
? ? ? ? 明確地定義模型所應用的上下文。根據團隊的組織、軟件系統的各個部分的用法以及物理表現(代碼和數據庫模式等)來設置模型的邊界。在這些邊界中嚴格保持模型的一致性,而不要受到邊界之外問題的干擾和混淆。
? ? ? ? Bounded Context明確地限定了模型的應用范圍,以便讓團隊成員對什么應該保持一致以及上下文之間如何關聯有一個明確和共同的理解。在Context中,要保證模型在邏輯上統一,而不用考慮它是不是適用于邊界之外的情況。在其他Context中,會使用其他模型,這些模型具有不同的術語、概念、規則和Ubiquitous Language的技術行話。通過劃定明確的邊界,可以使模型保持純粹,因而在它所適用的Context中更有效。同時,也避免了將注意力切換到其他Context時引起的混淆。跨邊界的集成必然需要進行一些轉換,但我們可以清楚地分析這些轉換。
? ? ? ? Bounded Context不是Module,有時這兩個概念易引起混淆,但它們是具有不同動機的不同模式。確實,當兩組對象組成兩個不同模型時,人們幾乎總是把它們放在不同的Module中。但人們也會在同一模型中用Module來組織元素,它們不一定要表達劃分Context的意圖。
識別Bounded Context中的不一致
? ? ? ? 很多征兆都可能表明模型中出現了差異。最明顯的是已編碼的接口不匹配。對于更微妙的情況,一些意外行為也可能是一種信號。采用了自動測試的Continuous Integration可以幫助捕捉到這類問題。但語言上的混亂往往是一種早期的警告信號。
? ? ? ? 將不同模型的元素組合到一起可能會引發兩類問題:重復的概念和假同源。重復的概念是指兩個模型元素(以及伴隨的實現)實際上表示同一個概念。每當這個概念的信息發生變化時,都必須更新兩個地方。每次由于新知識導致一個對象被修改時,必須重新分析和修改另一個對象。如果不進行實際的重新分析,結果就會出現同一概念的兩個版本,它們遵守不同的規則,甚至有不同的數據。更嚴重的是,團隊成員必須學習做同一件事情 的兩種方法,以及保持這兩種方法同步的各種方式。
? ? ? ? 假同源可能稍微少見一點,但它潛在的危害更大。它要是指使用相同術語(或已實現的對象)的兩個人認為他們是在談論同一件事情,但實際上并不是這樣。
? ? ? ? 當發現這些問題時,團隊必須要做出相應的決定。可能需要將模型重新整合為一體,并加強用來預防模型分裂的過程。分裂也有可能是由分組造成的,一些小組出于合理的原因,需要以一些不同的方式來開發模型,而且你可能也決定讓他們獨立開發。
三、參考文檔
DOMAIN-DRIVERN DESIGN
TACKLING COMPLEXITY IN THE HEART OF SOFTWARE
領域驅動設計
軟件核心復雜性應對之道
【美】Eric Evans 著 ? 趙俐 盛海艷 劉霞 等 譯