softwareArchitecture

細談元件耦合性

這篇文章討論 Clean Architecture 裡面的元件耦合性章節

圖片以及程式碼來源自Clean Architecture

耦合性

討論完了元件內部的內聚性 這篇文章來聊聊元件跟元件之間的關係 稱為耦合性(Coupling)

我們也曾經提到過 Coupling這個概念

本章再提出三個原則 來細談元件之間的耦合性 分別是

1.無環依賴原則

2.穩定依賴原則

3.穩定抽象原則

最後 我們會討論怎麼計算一個元件有沒有遵循這些原則 並給予量化

無環依賴原則 The Acyclic Dependencies Principle

Allow no circles in the component dependency graph

當我們將元件按照 deploy單位 來劃分時 每一個單獨的元件 可以由一個單獨的團隊來開發 當你要加新的功能 就把自己負責的元件改動之後 賦予一個新的版本號 讓使用你的人決定要不要使用或是什麼時候使用

這麼一來 就沒有一個團隊被另外一個團隊完全支配 對於一個元件的修改不必立即的反映到另一個元件上

這是一個簡單的合理的開發程序 但要成功執行 就必須對元件的依賴進行管理 元件的依賴中不能出現環

看個書上的例子

Alt text

無論從哪個元件開始 都無法按照箭頭走回同一個元件

這個有向圖非常清楚 比如說今天Presenters有了新版本 那就只有MainView需要仔細考慮他們何時需要跟Presenters整合

要發佈整個系統時 是從下而上發佈 也就是先編譯測試發佈Entities 一路下去最後再發佈Main

環來了

要是今天來了一個環 Entities指到Authorizer

Alt text

慘了 那今天要發佈Entities之前 要先確定Authorizer發佈成功 但Authorizer又要先等Interactor先成功 Interactor又要先等Entities 那就沒完沒了 發佈的時間上升 複雜度上升 測試難度也上升

解開環

解法一: DIP

Alt text

我們把User真正需要呼叫到的方法 用一個抽象分離出來 讓Authorizer實作這個抽象

這樣箭頭反向 依賴圖裡的環就不見了

解法二: 新開一個EntityAuthorizer都共同依賴的元件

Alt text

穩定依賴原則 The Stable Dependencies Principle

Depend in the direction of stability.

朝著穩定的方向進行依賴

什麼意思呢 如果一個元件他很可能會被變動 那我們就不要讓一個很難以改動的元件去依賴它 否則那個很可能會被變動的元件也會很難改動

穩定性

稍微定義一下專有名詞

下圖是個穩定的X Alt text

有三個元件依賴X 就有三個理由不去更改它 我們稱X對這三個元件負有責任(responsible) 但因為X不依賴任何人 任何外部影響都不會影響到X 所以我們稱X是無依賴性的(independent)

下圖是個不穩定的Y

Alt text

Y依賴於三個元件 我們稱Y是依賴性的(dependent)

穩定性metrics

Fan-In: 輸入依賴度 代表說多少外部元件依賴此元件內部的類別

Fan-Out: 輸出依賴度 代表多少此元件內部的類別依賴於別人

Instability: 不穩定性 I = (FO)/(FI+FO) 介於[0,1] 0代表非常穩定 1代表非常不穩定

上例子

Alt text

算一下Component C 的不穩定性: FI = 3, FO = 1, I = 1/4

那在程式語言中怎麼算呢 在C++裡面就看#include的數量 在Java就看import的數量

看回SDP

SDP告訴我們 要朝著穩定的方向進行依賴 代表說

一個元件的I值應該大於他所倚賴的元件的I值 或者是說

I值必須按著被依賴的方向逐漸減少 就是越下層應該越穩定

再看個應用

SDP怎麼應用到實務上呢 假設今天你是負責元件Flexible的工程師 這是個很容易被改動 你也預期會需要一直改動的元件 可是今天負責Stable的團隊 使用了你寫的一個類別

Alt text

好煩喔 因為別人依賴你 害你不能隨心所欲的改動 那你該怎麼辦呢? 沒錯 DIP

你仔細研究了一下 發現你的類別C被Stable裡面的類別U使用了

Alt text

於是我們建立一個US介面放進UServer元件裡 這樣我就解除了StableFlexible的依賴 兩者都依賴於UServer

UServer的I值是0 Flexible還是維持著我想要的不穩定性(I=1) 而且所有依賴都順著I減小的方向依賴

Alt text

只有一個介面的元件?

等等 你為了遵循SDP 多建了一個只包含介面的元件? 這個元件甚至不包含任何可以執行的程式碼 這合理嗎?

事實上 這很合理而且是個常見的必要策略 這些抽象的元件非常穩定(畢竟沒有任何實作) 因此是不太穩定的元件依賴的理想目標

穩定抽象原則 The Stable Abstraction Principle

A component should be as abstract as it is stable.

元件的抽象程度應該與元件的穩定程度一致

也就是說 一個穩定的元件也應該是抽象的 這代表說一個穩定的元件也要包含一些抽象類別 這樣就可對他進行擴展

來到了可愛的邏輯推理時間

SDP 告訴我們 要朝著穩定的方向進行依賴

SAP告訴我們穩定的元件就是抽象的元件

那SDP+SAP是什麼呢 答案是

依賴應該朝著抽象的方向進行

抽象性的metric

抽象性A怎麼計算呢 就是

(元件中抽象類別及介面的總數)/(元件中所有類別個數)

A介於[0,1] 0代表元件中沒有抽象類別 1代表元件中只有抽象類別

主角到齊了

Alt text

我們定義了不穩定性I 以及抽象性A 我們可以建立一個以I為橫軸 A為縱軸的座標圖

Alt text

你會發現最穩定的地方是座標圖的左上 最不穩定的地方是右下

注意 並不是所有元件都只落在這兩個地方 因為元件的抽象性跟依賴性有程度之分 比如你知道抽象類別也可能依賴於其他的抽象類別

但即便如此 還是有一些是元件不應該在的地方

Alt text

分別是右上角的無用地帶 以及左下角的痛苦地帶

無用地帶

這個地方 代表元件有著最大的抽象 但卻沒有任何人依賴它 活像個廢材

Alt text

痛苦地帶

在這裡的是高度穩定且具體的元件 我們不想要這種元件 因為他太具體所以很難進行擴展

而且要是這個元件很容易改變的話 那就加倍的痛苦了(因為很多人依賴它)

主序列

為了遠離無用地帶跟痛苦地帶 我們希望我們的元件可以分佈在(0,1)到(1,0)的線上 作者稱為主序列(Main Sequence)

既然我們知道越靠近主序列越好 那麼對於評價一個元件而言 我們就可以計算這個元件到主序列的距離

Alt text

當我們量化了一個元件的好壞以後 我們就可以盡情地分析我們的系統啦

你可以用任何你會的統計知識 mean(平均數) variance(變異數) SD(標準差)等等 把一個系統內的所有元件的座標畫在座標圖上

Alt text

當然也可以分析你不同的版本 來知道你的元件是不是越寫越偏了

Alt text

總結

本篇文章介紹了元件與元件之間的關係該如何評分 你可以使用這些關於依賴性管理的metrics 來知道你的系統的依賴性如何