[Note] Balancing Coupling in System Design

Cyan Ho
9 min readSep 22, 2023
Photo by Med Badr Chemmaoui on Unsplash

有幸在 DDD Taiwan 2023 年會中聽到 Learning Domain-Driven Design 作者 Vlad Khononov 現場的演講,這次演講的內容是在介紹他即將在 2024 年 1 月出版的新書 Balancing Coupling in Software Design 的核心概念,非常精彩,因此特地寫一篇文章記錄在演講中所學到的東西。

Component 在本文中是一個抽象的概念,可以是 Function、Class、Service,甚至是 System。

作者將 Components 之間的 Coupling 問題,建模成以下的數學式子:

Pain = Strength (S) * Volatility (V) * Distance (D)

在式子左邊的 Pain 可以理解為系統的維護成本,也是判斷 Coupling 為團隊造成了多少阻礙的參考指標。在式子右邊,Strength 表示 Components 之間 耦合的強度;Volatility 表示 Component 的變化頻率;Distance 表示 Components 之間的距離。

作者將系統的維護成本定義為這三個維度的乘積,且三項維度都會介於 0 到 1 之間。儘管模型中使用數字來呈現這些維度的影響程度,但現實世界中其實很難將它們量化為明確的數字。因此,這個模型更多是讓開發者意識到這三個維度,並且有目標地去調整它們,來讓維護系統的痛苦指數越小越好。

Strength

Strength 是用來衡量兩個 Components 之間的耦合強度,這個數值越高,表示 Components 之間的依賴關係越緊密。

作者在演講中介紹的完整語意應為 Integration Strength,為了維持上下文的一致性,在這篇文章裡統一使用 Strength。

假設現在有兩個 Components,其中 Component A(以下簡稱 A)依賴於 Component B(以下簡稱 B),如下圖所示:

Component A 依賴於 Component B

接下來將根據上面的例子,介紹作者將 Strength 進一步細分的四個層級,耦合關係由強到弱分別是:

Intrusive Coupling

A 依賴於 B 的實作細節,直接存取 B 的私有(private)資料和方法,而不是透過 B 的公開介面,這樣的做法會導致 A 變得非常脆弱(fragile),任何 B 的改動或重構,都可能會破壞 A 的功能。除此之外,B 無法確定 A 實際上用了哪些私有的資料或方法,這個隱晦(implicit)的耦合關係,也會造成 B 在開發上的阻礙。

Functional Coupling

A 和 B 涉及了相同的業務邏輯和流程,當業務規則改變時,會導致 A 與 B 需要同時更新。在現實中,A 與 B 甚至可能是兩個看似各自獨立的 Service,在業務規則異動時,需要有人意識到 A 與 B 之間隱晦(implicit)的耦合關係,否則很容易只改了 A 而忘了 B。

Model Coupling

A 直接引用 B 的資料結構(Data Structure)來做開發,實際上 A 可能只需要結構中的部分資料,當 B 調整了他的資料結構,就算異動的欄位 A 沒有使用到,也可能會連帶影響到 A 的實現。

Model Coupling 類似於過去的 Stamp Coupling

Contract Coupling

A 依賴於 B 的公開介面與資料結構,只要能確保介面保持一致,A 就不會受到 B 的內部改動所影響,B 也能隨心地調整實作細節,而不用擔心會影響到 A,屬於強度最低的耦合類型。

當 Strength 數值越高,代表 Components 之間的耦合關係越脆弱,任何改動都可能牽一髮而動全身,導致系統的維護成本上升。

Volatility

Volatility 是用來衡量一個 Component 的改動頻率,這個數值越高,表示 Component 越常被修改,例如,隨著業務成長而快速迭代的核心業務模組,就屬於高 Volatility 的 Component。

Component 每一次的改動,開發者除了需要確保 Component 本身邏輯的正確性,還需要測試與該 Component 相關的其他系統功能沒有受到影響。因此,當 Volatility 數值越高,代表 Component 改動頻率越高,需要投入更多人力與時間來測試改動的影響範圍,導致系統的維護成本上升。

Distance

Distance 是用來衡量兩個 Components 之間的距離,距離從近到遠大致上可分為 Statements、Functions、Classes、Modules、Services 與 Systems。例如,兩個 Functions 之間的依賴關係,距離會小於兩個 Classes 之間的依賴關係,因此會獲得較低分的 Distance 數值。

作者在演講中提及的分類為 Statements、Methods、Classes、Namespaces、Components、(Micro)Services 與 Systems。由於 Components 在此的意義與文章其他部分提及的 Component 概念不同,為避免混淆,筆者將 Namespaces 與 Components 合併簡化為 Modules。

想像一下,若一個業務功能背後涉及了兩個獨立團隊開發的兩套獨立系統,當這個功能需要調整時,勢必需要兩個團隊共同參與這項任務才能完成。因此,當 Distance 數值越高,代表 Components 之間的功能調整,會產生更多團隊間的協作成本,導致系統維護的成本上升。

在理解 Strength、Volatility 和 Distance 的概念後,讓我們再次把注意力拉回這個公式上:

Pain = Strength (S) * Volatility (V) * Distance (D)

作者巧妙地將 Pain 定義為三個維度的乘積,根據乘法的性質,不管任意兩個維度的數值有多高,只要剩下的那個維度數值足夠低,就能有效的降低系統的維護成本。例如,當 Components 之間的 Strength 與 Volatility 都很高時,可以試著降低它們的 Distance,例如將兩個獨立的 Services 合而為一,來減少系統維護的成本。

接下來讓我們從一些過往熟悉的模式,來理解三個維度相互平衡的關係。

Aggregate

業務邏輯是軟體系統中最重要且複雜的部分,隨著業務的發展,業務邏輯必須因應產品需求的演進進行頻繁的迭代,而複雜的邏輯必須依靠系統內不同的 Components 交互協作才得以實現。

因此,系統的業務邏輯本質上具有高 Strength 和高 Volatility 的特性,在這個既定限制之下,根據 Coupling 的模型,為了降低業務邏輯的維護成本,我們唯一能做的是嘗試降低第三個維度 Distance,也就是參與實作業務邏輯的Components 之間的距離,這正是 DDD 戰術設計中 Aggregate 所要達成的目的。

Aggregate 在 DDD 裡負責掌管領域中最核心的業務邏輯,透過明確劃分出業務操作的交易邊界,將實作業務邏輯所需的 Components 都納入到 Aggregate 邊界之內,這個過程實質上就是在降低這些 Components 之間的 Distance,讓它們能在同一個地方封裝管理,降低維護成本。

Pain = 0 = (S = 1) * (V = 1) * (D = 0)

Microservice

隨著組織的成長,可能漸漸演化出各個團隊維護各自業務服務的系統架構,雖然讓多個服務共享單一資料庫可以降低服務之間交換資料的不便,但這卻是微服務設計裡極力避免的模式。

團隊各自維護獨立的服務已經在系統內大大增加了 Distance,每個團隊能夠掌握自己服務的開發步調也進一步提升了 Volatility,若此時還讓多個團隊共用一個資料庫,Strength 也會得到一個很高的數值。

因此在微服務設計中,為每個微服務建置屬於自己的資料庫,就是在高 Volatility 與高 Distance 的環境限制下,將 Strength 從單一資料庫共享私有狀態的 Intrusive Coupling,降低為透過服務公開介面分享資訊的 Contract Coupling,來平衡整個系統的維護成本。

Pain = 0 = (S = 0) * (V = 1) * (D = 1)

有點忘記作者演講時透過降低 Strength 來平衡維護成本所舉的例子,這個例子是我後來想到的,希望有把這個情境表達出來。

Legacy System

當服務必須高度依賴於一個外部系統,也就是在 Strength 與 Distance 都很高的情況下,若能確保該系統不再更新,即擁有很低的 Volatility,則其他服務耦合於它並不會增加 Coupling 所產生的維護成本,Legacy System 就是一個符合這個條件的例子。

Legacy System 在這裡代表的是一個能夠提供完整功能,但因為各種因素而不再維護的系統。當確定這個系統不再有任何更新後,低 Volatility 所帶來的穩定性,能夠大幅降低與它耦合所帶來的維護成本。

Pain = 0 = (S = 1) * (V = 0) * (D = 1)

結語

作者提出這個用來衡量 Coupling 的模型,筆者認為更多是讓開發者能夠意識到 Strength、Volatility 和 Distance 這三個維度和系統維護成本之間的關係,並在優化系統架構時能有一個評估和參考的方向。在現實世界中,其實很難為這三個維度定義出很明確的數值,最終計算出來的 Pain,也很難有一體適用的標準來衡量架構的好壞。

雖然 DDD Taiwan 還未將今年大會的錄影公開,有興趣的讀者可以先參考 Vlad Khononov 今年 5 月在 Code Europe 同主題的演講:

Balancing Coulping in Software Design, by Vlad Khononov, in Code Europe 2023 Tech Festival

更多詳細的內容,可以期待 2024 年 1 月書籍的出版:Balancing Coupling in Software Design

後記

在演講最後的 QA 環節,有人問作者是什麼原因啟發你寫這本新書。作者回答說,他曾經參與過一個使用 Microservice 作為架構的專案,最後那個專案失敗的很徹底,因此激發他想更深入研究 Coupling 這個議題。

其實大神跟普遍的開發者一樣,也會犯錯,並且從錯誤中學習成長,只是他們在解決問題的途中,已經飛到不知道哪個世界去了。

--

--