文章同步於it邦
前言
今天我們要來說說,元件、元件內聚性以及元件耦合性
大家一定聽過所謂的高內聚低耦合
所以內聚是甚麼,耦合是什麼
高耦合不好嗎
今天就來介紹
元件是什麼
元件(Component)是部屬(deployment)的單位。根據不同的語言有所不同,在Java中是jar檔。在Ruby中,他們是gem檔。在直譯語言中,他們是原始檔的集合。
元件內聚性
哪個類別該屬於哪個元件,其實非常的重要,而這有賴於良好的工程原則來指引。不幸的是,多年來,這個決定卻幾乎完全只是依據現場情境而臨時做出的決定。
-Clean Architeucture (P89)
再使用性 - 發佈等價原則(REP)
這邊其實有點難懂,我把它翻譯成我的話來解釋。
當我們在使用模組的時候,有時候我們會直接不指定版本來做更新並且上Git做版控
那此時就會有個問題,我們通常不會把整包依賴的模組(ex: PHP compose的vender,Python各種模組)全部丟上遠端倉庫,如果真的要改也會繼承出來去做修改,而不去更動source code
但在Clean Architecture的要求是,這邊希望把模組和類別一起被發佈出去。這其實是為了說,往後我們依賴的模組被更新時,我們可以選擇我們需要的版本,而不是無腦進版。
這邊分享一下我們的做法,通常我會指定版本,而我如果需要更改Source Code 我會先確定能不能繼承出來改,如果不行我才會直接上傳整包模組和套件。
這邊的重點就是,管理好我們所使用的模組和套件以及他的版本。
共同封閉原則(CCP)
如果說單一職責原則(SRP)規範了一個類別不該負責多個角色,那 CCP 規定了一個元件不該包含多個引起變化的原因。
在大多數的程式中,可維護性的重要性是超過可重用性的。如果Code必須被更改,那麼我寧願只修改一個地方,而不是到處修改
CCP 鼓勵我們把可能基於相同原因而更改的所有類別共同聚集到一個地方。如果兩個類別之間有很緊密的關係,那麼他們應該屬於同一元件。
舉個例子:
假設我們在撰寫一個計算學生成績的API,而我需要固定將各種科目做加權,那此時我們就可以把這個加權的數值訂為一個常數
那有幾個科目就有幾個常數(不要跟我說兩個科目可以共用,不要這樣),那我們就可以把這些常數在順便放到同一元件底下去做統一管理
把那些在同一時間和相同的原因改變的東西聚集在一起。把那些在不同的時間或不同的原因改變的東西分離開來
-Clean Architeucture (P92)
共同重複使用原則(CRP)
不要強迫元件的使用者依賴他們不需要的東西
-Clean Architeucture (P92)
是不是覺得這段話那裡聽過,沒錯就是ISP
所以我必須很殘酷地告訴你,對他基本上就是ISP的架構版
把這兩個合成一個建議就是
不要依賴你不需要的東西
-Clean Architeucture (P93)
元件耦合的張力圖
我們可以看到這張圖,它說明了這三個原則如何互相拉鋸
因為前兩個原則是將架構變大,最後則是縮小
所以我們要如何規劃這個架構就成了很重要的課題
通常在專案初期,我們會選擇犧牲重用,直到後期我們才會慢慢地往元件的重用性來移動。
我想這個對於有讀過Clean Architecture的人來說會特別有感
當你開始做 CCP 的時候,你通常會覺得,恩這些可以寫一起吧,好像都是相同邏輯。
但我個人認為,初期把一些職責切清楚會比較好。就像某些人會建議,如果說真的重複的地方有超過多少個,我們再把它做在一起。
元件耦合性
無環依賴原則(ADP)
不知道大家是不是遇過一個問題,前一天寫的Code,隔天早上來公司發現不能用,結果發現是因為你依賴的底層模組的那個作者(同事A)改了一些東西,而導致你的Code廢掉。然後因為你的Code廢掉,結果另一個同事(同事B)也跟著不能使用。再來同事B不能用,結果同事A也不能跟著改了。
有發現一個問題嗎,現在的依賴是:你依賴同事A的元件,然後同事A依賴同事B,同事B在依賴你。
這形成了一個無限迴圈。
這個原則講的就是,我們必須讓元件可以有方向性,且沒有環。也就是我們可以從任一元件開始然後都不會走到同一個地方或走過的地方。
當環出現的時候,我們要先想辦法恢復成沒有環的狀態,也就是有方向但沒有環。
固定依賴原則(SDP)
聖地牙哥教士
對於任何元件而言,如果預期他可能會有變化,就不要讓另一個更難改的元件去依賴他。
而何謂穩定的元件,就是只說多個元件依賴此元件,但這個元件卻不依賴。這就是一個穩定的原件,反之則不穩定。
但你說一堆全部都是的穩定元件這樣好嗎。其實也不好,因為這樣你的系統就改不動了。
所以一個理想的狀態是怎麼樣,也就是我們元件必須要往下層依賴,把不穩定的原件都放在頂部,而底部則放各種穩定元件。
舉個例子:
當我的架構是包含了Database、UseCase、API這三層
那我就會希望依賴的順序是這樣 API -> UseCase -> Database
任何反向的箭頭都違反了SDP
穩定抽象原則(SAP)
一個穩定的元件他應該是抽象的,這樣他的穩定性就不會阻止他拓展。另外不穩定的元件應該是具體的,這使得內部具體的Code容易被修改。
將SDP與SAP結合,就會變成依賴應該朝著抽象的方向進行
那我們來修改一下架構就會變成,再將Database依賴到最底下的抽象層,也就是規定各層實作的方法以及介面會長怎麼樣。
結語
我只能說,今天塞這些真的是非常非常多的內容,我只能將它簡化將重點擷取出來消化再翻譯給你們。
不然要整個講完我可能會先葛屁
參考資料
Clean Architeucture(CH12)
A primer on the clean architecture pattern and its principles
細談元件內聚性
細談元件耦合性