[譯文]Domain Driven Design Reference(五)—— 為戰略設計的上下文對映

Zachary_ZF發表於2019-03-03

本書是Eric Evans對他自己寫的《領域驅動設計-軟體核心複雜性應對之道》的一本字典式的參考書,可用於快速查詢《領域驅動設計》中的諸多概念及其簡明解釋。

其它本系列其它文章地址:

[譯文]Domain Driven Design Reference(一)—— 前言

[譯文]Domain Driven Design Reference(二)—— 讓模型起作用

[譯文]Domain Driven Design Reference(三)—— 模型驅動設計的構建模組

[譯文]Domain Driven Design Reference(四)—— 柔性設計

[譯文]Domain Driven Design Reference(五)—— 為戰略設計的上下文對映

繫結上下文

  對一個特定模型的定義和適用範圍(通常是一個子系統,或特定團隊的工作)的描述。

上游-下游

  兩個組之間的關係是“上游”小組的行為影響“下游”小組的專案成功。但下游的行為並不會顯著影響上游專案。(例如,如果兩個城市沿著同一條河流,上游城市的汙染主要影響下游城市。)

  上游團隊可以獨立於下游團隊的命運而取得成功。

相互依賴

  必須在不同的上下文中交付兩個軟體開發專案以使其中任何一個被認為是成功的情況。(當兩個系統各自依賴另一個系統的資訊或功能時,我們通常會盡量避免將看到的專案構建成相互依賴的。 然而,也有一些相互依賴的專案,系統依賴性只向一個方向發展。當依賴系統沒有其它的系統與該系統的整合時,它幾乎沒有任何價值,或許因為這是唯一一個使用它的地方,那麼未能提供依賴系統就會導致兩個專案都失敗。)

自由

  一個理想中的軟體開發上下文,在其它上下文中的開發工作是成功或失敗對其自己的交付沒有什麼影響。

上下文對映

  為了策劃戰略,我們需要一個現實的,大範圍的模型開發檢視,擴充套件到我們的專案和我們整合的其他專案。

  在沒有全域性檢視的情況下,個別限界上下文會遺留下一些問題。其他模型的上下文可能仍然是模糊不清的。

  其他團隊的人不會意識到上下文的界限,並且會在不知不覺中做出一些模糊邊緣或使內部連線複雜化的改變。當連線必須在不同的上下文中進行時,它們往往會相互滲透。

  即使邊界清晰,與其他上下文的關係也會限制模型的性質或可行的變化速度。這些制約因素需要通過非技術渠道表現出來,有時很難與他們正在影響的設計決策聯絡起來。

  因此:

  識別專案中正在使用的每個模型並定義它的限界上下文。這包括非物件導向子系統的隱式模型。給每個限界上下文命名,並且使其名稱成為通用語言的一部分。

  描述模型之間的聯絡點,列出對任何互動的明確翻譯,突出任何共享、隔離機制和影響程度。

  對映現有的領域範圍。稍後再進行轉換。

  這張對映圖可以成為實際設計策略的基礎。

  在接下來的幾頁中,關係的描述會變得更加具體,在限界上下文之間有一組通用的關係模式。

合作關係*

  當兩個上下文中的團隊共同成功或失敗時,通常會出現合作關係。

  在相互獨立的上下文中,相互依賴的子系統缺少協作會導致兩個專案的交付失敗。一個系統缺失的一個關鍵特性可能會使另一個系統無法交付。不符合其他子系統開發人員期望的介面可能導致整合失敗。一個相互約定的介面可能會變得過於彆扭,以致於減慢了客戶端系統的開發速度,或者很難實現,從而減慢了服務端子系統的開發速度。失敗帶來了兩個專案的失利。

  因此:

  如果兩個上下文中的任何一個開發失敗都將導致兩個上下文的交付一起失敗,則在負責這兩個上下文的小組之間建立合作關係。制定協調發展和聯合管理一體化的過程。

  團隊必須在其介面的演進上進行協作,以適應這兩個系統的開發需求。應該安排相互依賴的feature,以便它們在同一版本中完成。

  大多數情況下,開發人員不需要詳細瞭解其他子系統的模型,但他們必須協調他們的專案計劃。當一個上下文中的開發遇到障礙時,則需要聯合研究這個問題,以找到一種緊急的設計解決方案,而不會過分地損害任何一方。

  此外,還需要一個清晰的過程來管理整合。例如,可以定義一個特殊的測試套件,以證明介面符合客戶端系統的期望,它可以作為伺服器系統上持續整合的一部分執行。

共享核心

  共享模型和相關程式碼的一部分是非常密切的相互依賴關係,它能夠加快設計工作或者破壞這些共享的東西。

  當功能整合受到限制時,大型上下文的持續整合的開銷可能會被認為太高。當團隊沒有足夠的技能或組織架構來維持持續整合,或者單個團隊的規模太大而笨拙時,這種情況可能尤為明顯。因此,可以定義獨立的限界上下文,並形成多個團隊。

  一旦獨立的、不協調的團隊在密切相關的應用程式上工作,可能會向前推進一段時間,但是他們生產的產品可能不適合在一起。即使是合作伙伴團隊最終也會花費大量精力在翻譯層和改造上,同時重複這些工作並失去通用語言的好處。

  因此:

  用明確的邊界指定團隊同意分享的領域模型的一部分子集。保持這個核心儘可能的小。

  在這個邊界內,包括模型的子集,程式碼的子集,或者與該模型的部分相關聯的資料庫設計。這種顯式共享的內容具有特殊的地位,在未與其他團隊協商的情況下不應改變。

  定義一個持續整合過程,以保持核心模型的緊湊性,並與團隊的通用語言保持一致。經常其整合功能系統,雖然比團隊中持續整合的次數要少一些。

客戶/供應商開發

  當兩個團隊處於上下游關係時,上游團隊可能獨立於下游團隊的命運而取得成功,下游的需求將以各種各樣的方式得到解決,並帶來廣泛的負面後果。

  下游的團隊可能是無助的,受上游優先順序的擺佈。與此同時,上游團隊可能會收到抑制,擔心會破壞下游系統。擁有複雜審批流程的繁瑣的變更請求過程並沒有改善下游團隊的問題。如果下游團隊對變更擁有否決權,上游團隊的自由發展就會停止。

  因此:

  在兩個團隊之間建立清晰的客戶/供應商關係,意味著將下游優先因素放到上游的規劃中。為下游需求進行談判和預算任務,以便每個人都瞭解承諾和時間表。

  敏捷團隊可以在規劃會議中讓下游團隊扮演上游團隊的客戶角色。聯合開發的自動化驗收測試可以驗證來自上游的預期介面。將這些測試新增到上游團隊的測試套件中,作為其持續整合的一部分,將使上游團隊自由地進行更改,而不必擔心下游的副作用。

順從者

  當兩個開發團隊有一個上下游關係時,上游沒有動力為下游團隊的需求提供幫助,下游團隊就無能為力了。利他主義可能會促使上游開發者做出承諾,但它們不太可能實現。相信這些好意會導致下游團隊基於無法獲得的特性來制定計劃。下游專案將被推遲,直到團隊最終學會接受上游所提供的東西。針對下游團隊的需求量身定製的介面是不太不可能的。

  因此:

  通過對上游團隊的模型進行嚴格的遵守,消除了限界上下文之間的轉換的複雜性。儘管這限制了下游設計人員的風格,並且可能不會產生應用程式的理想模型,但是選擇一致性極大地簡化了整合。此外,你將與上游團隊共享一種通用語言。上游在駕駛員的位置上,所以讓他們的交流變得容易是件好事。利他主義可能足以讓他們與你分享資訊。


反腐層

  當與合作團隊銜接良好設計的限界上下文時,翻譯層可以是簡單的,甚至是優雅的。但是,當控制或通訊不足以實現共享核心、合作伙伴或客戶供應商關係時,轉換就變得更加複雜。翻譯層採用了一種更具防禦性的語氣。

  一個提供給上游系統的大型介面最終可能完全顛覆下游模型的意圖,從而使其被修改成以一種特別的方式來模仿其他系統的模型。遺留系統的模型通常是很薄弱的(如果不是大泥球的話),即使是明確設計的例外也可能不符合當前專案的需求,這使得遵循上游模型變得不切實際。然而,這種整合對於下游專案可能非常有價值甚至是必需的。

  因此:

  作為下游客戶端,建立一個隔離層,根據您自己的領域模型,為系統提供上游系統的功能。該層通過其現有的介面與另一個系統進行通訊,只需要很少或不需要對其他系統進行修改。在內部,這一層在兩個模型之間需要單向或雙向轉換。


開放主機服務

  通常對於每個限界上下文,您將為每個部件定義一個翻譯層,您必須將其與上下文之外的元件整合在一起。在整合是一次性的情況下,為每個外部系統插入翻譯層的這種方法以最小的成本避免了模型的損壞。但是當你發現你的子系統有更高的要求時,你可能需要更靈活的方法。

  當一個子系統必須與許多其他的子系統整合時,為每一個子系統定製一個翻譯物件可能會使團隊陷入困境。有越來越多的維護,越來越多的擔心什麼時候會發生變化。

  因此:

  定義一個協議,將訪問您的子系統作為一組服務。 開啟協議,使所有需要與您整合的人都可以使用它。增強和擴充套件協議以處理新的整合需求,除非一個團隊有特殊的需求。然後,使用一次性翻譯物件來增強該特殊情況的協議,以便共享協議能夠保持簡單和一致。

  這將使服務提供者處於上游位置。每個客戶端都在下游,並且通常其中一些客戶端會遵守規定,有些客戶端會建立反腐層。具有開放主機服務的上下文可能與它的客戶端以外的上下文有任何關係。

公共語言

  兩個限界上下文模型之間的轉換需要一種通用語言。

  直接轉換到現有的領域模型可能不是一個好的解決方案。這些模型可能過於複雜或被分解得很糟糕。也許他們說的是非法的。如果將其中一種用作資料交換語言,它實際上就會被凍結,不能響應新的開發需求。

  因此:

  使用一種文件完整的公共語言,可以將必要的領域資訊作為一種通用的通訊媒介來表達,並根據需要翻譯為該語言。

  許多行業以資料交換標準的形式建立了公共語言。專案團隊也開發自己的,在他們的組織內使用。

  公共語言通常與開放主機服務相結合。

分而治之

  在定義需求方面,我們必須冷酷無情。如果兩組功能之間沒有顯著的關係,它們可以完全相互分離。

  整合總是代價很大的,有時候好處很小。

  因此:

  宣告一個限界上下文,使其與其他上下文完全沒有關聯,允許開發人員在這個小範圍內找到簡單的、專門的解決方案。


大泥球

  在我們調查現有的軟體系統時,我們試圖瞭解不同的模型在定義的邊界內是如何被應用的,我們發現部分系統(通常是大型系統),模型是混合的,邊界是不一致的。

  在沒有邊界的系統中,試圖描述模型的上下文邊界很容易陷入困境。

  定義良好的上下文邊界作為知識選擇和社會力量的結果出現(儘管建立系統的人在當時可能並不總是有意識地意識到這些原因)。當這些因素缺失或消失時,將多個概念系統混合在一起,使得定義和規則變得模稜兩可或相互矛盾。隨著特性的新增,系統是根據附加的邏輯來工作的。依賴關係縱橫交錯。因果關係變得越來越難以追蹤。最終,軟體會凝結成一個大的泥球。

  在某些情況下,大球泥實際上是非常實用的(正如Foote和Yoder的原文所描述的那樣),但它幾乎完全阻止了有用模型所需要的敏銳和精確性。

  因此:

  在整個混亂的周圍畫一個邊界,把它指定為一個大泥球。不要嘗試在此上下文中應用複雜的建模。要警惕這種系統向其他上下文蔓延的趨勢。

  (見http://www.laputan.org/mud/mud.html。Brian Foote和Joseph Yoder)

作者:Zachary_Fan
出處:www.cnblogs.com/Zachary-Fan…

如果你想及時得到個人自寫文章的訊息推送,歡迎掃描下面的二維碼~。

相關文章