softwareArchitecture

細談元件內聚性

這篇文章討論 Clean Architecture 裡面的元件內聚性章節

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

內聚性

我們曾經提到過 Cohesion這個詞 指的是一個元件裡面不同單元的關聯性

本章再提出三個原則 來細談元件內部的內聚性 分別是

1.再使用性/發佈 等價原則

2.共同封閉原則

3.共同重複使用原則

再使用性/發佈 等價原則 The Reuse/Release Equivalence Principle

The granule of reuse is the granule of release

這句話乍看之下有點難理解 但其實它說的是

The unit of reuse is the unit of release

當我們想reuse別人的程式碼的時候 如果我們只是單純的複製貼上 那未來如果那段程式碼被改動了(修bug或加feature) 我們就要隨著它修改 這實在太廢了

我們希望的是 藉由import那段程式的版本號 來reuse但段程式碼 這樣每次他有新的更新的時候 你就可以去參考一下 看你需不需要增加版本號來引入那段改動

聽起來很合理 那跟REP什麼關係呢 我的解讀是

把你想要同時Release的單元放進同一個元件(讓別人Reuse)

當你有這個概念之後 如果你放了太不相關的東西到你的元件裡 引用了你的元件的人就會覺得:

搞啥 這個改動跟這個元件關聯在哪?

相反的 我相信你想要讓引用你的人覺得:

喔好吧 為了這個改動而改動我的版本號也是挺合理的

所以REP告訴了我們 哪些東西應該被包在一起 一起Release 一起被Reuse

共同封閉原則 The Common Closure Principle

Gather into components those classes that change for the same reasons and at the same times. Separate into different components those classes that change at different times and for different reasons.

將會在相同時間 因為相同理由而發生變化的類別放在一起

這個… 根本就是單一職責原則的Component版本嘛

因為如果兩個有相同更改理由的單元被放進不同的元件裡 那當這個更改的理由發生時 我就要改動/發佈兩個以上的不同元件

Alt text

合理

共同重複使用原則 The Common Reuse Principle

Don’t force users of a component to depend on things they don’t need.

這… 根本就是介面分割原則換句話說嘛

Alt text

可見基礎多麼重要

元件內聚性的張力圖

看完了這三個原則 也許你會覺得這三個原則有點戶相拉扯的感覺

REP和CCP是包容性原則(Inclusive) 這兩個傾向於讓元件變更大

CRP是一個排除性原則(Exclusive) 這個原則傾向讓元件變更小

下圖是元件內聚性的張力圖

Alt text

稍微翻譯翻譯

如果你太過注重REP和CCP 那麼你的架構就會需要太多沒必要的release

如果你太過注重CCP和CRP 那麼你的架構就會很難reuse

如果你太過注重CRP和REP 那麼你的架構每次改動都會動到很多元件

那我知道了 是不是剛好在這個三角形重心處就是個完美的架構呢 其他的都有待改善?

Alt text

應該說 好的架構師 會知道現在的團隊應該在哪個位置會對團隊最有利 這個問題的答案可能會隨著時間改變

舉個例子 在一個開發團隊的初期 你應該注重CCP > REP 因為開發難易度比重用度重要

我有問題

為什麼這裡的Cohesion這麼複雜呢 之前講內聚性的時候不就是越高越好嗎?

之前我們講的是一個類別或是一個函式 規模比較小 在這裡我們講的是元件內聚性

元件是什麼? 元件是可以被部署(deploy)的最小單位(在Java裡面是jar檔 Ruby裡面是gem檔)

既然我們討論的規模變大了 那就不能只是單純的Cohesion越高越好了 還得考慮reuse的難易程度 release的次數等等

總結

這三個原則描述了元件之中更為複雜的內聚性 告訴了我們在選擇哪些單元要放在哪些元件裡的時候 我們要考慮可重用性和可發展性

在應用程式的需求和這三個原則中取得平衡是很難的任務