微服務領域驅動設計 - semaphoreci

banq發表於2022-06-30

微服務是開發軟體的最具可擴充套件性的方式。但是你需要一個好的設計,讓開發團隊自主工作和部署,而不會互相干擾,否則你將失去可擴充套件性的好處。
領域驅動開發允許我們通過將更大的系統分解為獨立的單元、瞭解每個單元的職責並確定它們之間的關係來規劃微服務架構。在本文中,我們將學習領域驅動設計的基礎知識以及如何將其應用於微服務。

什麼是領域驅動設計?
領域驅動設計 (DDD) 是一種軟體設計方法,開發人員在其中構建模型以瞭解領域的業務需求。這些模型作為開發軟體的概念基礎。
根據域驅動設計的作者 Eric Evans 的說法:解決軟體核心的複雜性,領域是:

知識、影響或活動的領域。使用者應用程式的主題領域是軟體的領域。

一個人解決問題的能力取決於一個人對該領域的理解能力。開發人員是聰明人,但他們不可能是所有領域的專家。他們需要與領域專家合作,以確保程式碼符合業務規則和客戶需求。

微服務領域驅動設計 - semaphoreci
上圖說明:開發人員和領域專家使用統一的語言來共享知識、文件、計劃和程式碼。

微服務架構的兩個最重要的 DDD 概念是:有界上下文上下文對映

限界/有界上下文 (BC)
單詞出現的環境決定了它的含義。根據上下文,“書”可能指的是書面作品,也可能意味著“預訂房間”。有界上下文(BC)是一個術語具有明確和明確含義的空間。
在 DDD 之前,通常的做法是嘗試找到一個跨越整個領域的模型。問題是域越大,就越難找到一致統一的模型。DDD 的解決方案是識別 BC,以便將域分解為可管理的子域。

微服務領域驅動設計 - semaphoreci
在軟體中,我們需要精確。這就是定義 BC 至關重要的原因:它為我們提供了一個精確的詞彙表,稱為通用語言,可用於開發人員和領域專家之間的對話。無處不在的語言存在於整個設計過程、專案文件和程式碼中。

上下文對映
BC 的存在預示著對通訊渠道的需求。例如,如果我們在電子商務領域工作,銷售人員應該在銷售產品之前檢查庫存。一旦售出,就需要通過運輸來確保將產品送到正確的地址。在 DDD 中,這些關係以上下文對映的形式描述。

微服務領域驅動設計 - semaphoreci

微服務領域驅動設計
DDD 分兩個階段進行:

  1. 戰略階段,我們確定 BC 並將它們對映到上下文地圖中。
  2. 戰術階段,我們根據子域的業務規則對每個 BC 進行建模。

讓我們看看每個階段如何在微服務架構設計中發揮作用。

1、戰略階段
在此階段,我們邀請開發人員、領域專家、產品所有者和業務分析師進行頭腦風暴、分享知識並制定初步計劃。在主持人的幫助下,這可以採取事件風暴研討會的形式,我們在其中構建模型並從領域中的重大事件開始識別業務需求。

微服務領域驅動設計 - semaphoreci
在戰略 DDD 中,我們採用高層次、自上而下的設計方法。我們首先分析域以確定其業務規則。由此,我們得出一個 BC 列表。

微服務領域驅動設計 - semaphoreci
邊界充當天然屏障,保護內部模型。因此,每個 BC 都代表了一個實現至少一個微服務的機會。

微服務領域驅動設計 - semaphoreci
接下來,我們必須決定 BC 將如何通訊。Eric Evans列出了七種型別的關係,而其他作者列出了其中的六種。不管我們如何計算它們,至少三個(共享核心、客戶/供應商和遵從者)意味著緊密耦合,這是我們在微服務設計中不想要的,可以忽略不計。這給我們留下了四種型別的關係:

  • 開放主機服務(OHS):服務提供者定義一個開放協議供其他人使用。這是一種開放式的關係,因為消費者需要遵守協議。
  • 已釋出語言(PL):此關係使用眾所周知的語言,例如 XML、JSON、GraphQL 或任何其他適合該領域的語言。這種型別的關係可以與 OHS 結合使用。
  • 反腐敗層(ACL):這是服務消費者的防禦機制。反腐敗層是在下游服務之前實現的抽象和翻譯包裝層。當上遊發生變化時,消費者服務只需要更新 ACL。
  • 不同的方式:當進一步分析發現兩個服務之間的整合沒有什麼價值時,就會發生這種情況。這與關係相反——這意味著 BC 沒有聯絡,也不需要互動。

在我們的戰略 DDD 分析結束時,我們得到一個詳細描述 BC 及其關係的上下文圖。

微服務領域驅動設計 - semaphoreci

戰術階段
在內心深處,軟體開發是一種建模練習;我們將現實生活中的場景描述為模型,然後用程式碼解決它。在上一階段,我們確定了 BC 並繪製了它們的關係。在這個階段,需要開發人員精通 DDD 理論,我們將放大每個上下文以構建詳細的模型。
使用 DDD 建立的模型與技術無關——它們沒有說明底層的堆疊。相反,我們專注於對子域進行建模。我們模型的主要構建塊是:

  • 實體:實體是具有隨時間持續存在的身份的物件。實體必須具有唯一識別符號(例如,客戶的帳號)。雖然實體識別符號可以在上下文邊界之間共享,但實體本身不需要在每個 BC 中都相同。每個上下文都可以擁有給定實體的私有版本。
  • 值物件:值物件是沒有標識的不可變值。它們代表您模型的原語,例如日期、時間、座標或貨幣。
  • 聚合:聚合建立實體和值物件之間的關係。它們代表一組可以被視為一個單元並且始終處於一致狀態的物件。例如,客戶下訂單並擁有書籍,因此可以將實體 customer、order 和 book 視為一個聚合。聚合必須始終由稱為根實體的主實體引用。
  • 領域服務:這些是實現業務邏輯或功能的無狀態服務。域服務可以跨越多個實體。
  • 領域事件:對於微服務設計至關重要,領域事件會在發生某些事情時通知其他服務。例如,當客戶購買一本書時,付款被拒絕,或者使用者已經登入。微服務可以同時產生和消費來自網路的事件。
  • 儲存庫:儲存庫是聚合的持久容器,通常採用資料庫的形式。
  • 工廠:工廠負責建立新的聚合。

微服務領域驅動設計 - semaphoreci

領域驅動設計是迭代的
雖然看起來我們必須首先編寫一個詳盡的領域描述,然後才能開始處理程式碼,但現實情況是,DDD 與所有軟體設計一樣,是一個迭代過程。
在紙面上,限界上下文和上下文對映可能看起來不錯,但在實施時,它們可能會轉化為太大而無法正確稱為微服務的服務。相反,具有重疊職責的聊天微服務可能需要合併為一個。
隨著開發的進展,您對領域有了更好的理解,您將能夠做出更好的判斷、增強模型並更有效地進行溝通。

更多設計微服務的方法
DDD 無疑是一種重理論的設計模式。因此,僅當正在開發的系統足夠複雜以保證額外的規劃工作時才推薦使用。
其他方法,例如測試驅動開發(TDD) 或行為驅動開發(BDD),對於更小、更簡單的系統可能就足夠了。TDD 在處理單個微服務或什至僅由少數服務組成的應用程式時是最快的開始並且效果最好。

在更大的範圍內,我們可以使用 BDD,它迫使我們通過整合和驗收測試來驗證批發行為。如果您從事低到中等複雜度的設計,BDD 可能會很好地工作,但是一旦您達到某個閾值,維護測試可能會減慢您的速度。

您還可以將這三種模式結合起來,為每個開發階段選擇最好的一種。例如:

  1. 識別微服務及其與戰略 DDD 的關係。
  2. 使用戰術 DDD 對每個微服務進行建模。
  3. 由於每個團隊都是自治的,因此他們可以選擇採用 BDD 或 TDD(或兩者混合)來開發微服務或微服務叢集。

相關文章