架構整潔之道導讀(二)
我是《架構整潔之道》( Clean Architecture ) 中文版的技術審校者,在審校的過程當中略有感悟,所以希望通過撰寫導讀的方式分享給大家。
元件聚合
元件的定義
元件是軟體部署的最小單元,是整個軟體系統在部署過程中可以獨立完成部署的最小實體。比如,對於Java應用程式而言,Jar包就是元件;Ruby中的元件則是Gem檔案;Python中的Egg或Wheel檔案以及.Net下的DLL檔案。
上回我們說到,程式設計正規化的本質是約束。子過程、類或函式是我們程式設計過程中的基本元素,所以說程式設計正規化是程式的基礎構件。如果將這些基本構件比作建築裡的泥沙石,那麼程式中的元件就可以類比成磚頭。磚頭的工藝注重材料配比,元件也是如此,恰如其分的基礎構件配比是元件穩定的基礎。元件的內容配比較難定量,但是在實踐上,仍然受到指導原則的約束。
軟體工程中的約束三角
在軟體工程中,我們會看到很多約束條件都能由三角形的方式體現出來。這是因為三角形除了具有穩定的特性以外,還能體現出一種張力。

軟體開發中的各種三角
比如在敏捷專案管理中,我們常會聽到時間,資源和成本的約束三角;在分散式計算中,著名的CAP(一致性,可用性和分割槽容錯性)原理也是如此;還有區塊鏈中的不可能三角(效能,安全和去中心化)。這些三角都在反映一種約束——不能完全同時滿足,需要權衡。
元件聚合張力圖
元件的內容配比,最終反映在元件的實踐上就是基本構件的拆與合。鮑勃大叔給出了三個拆合的指導原則:REP(複用/釋出等同原則),CCP(共同閉包原則)和CRP(共同複用原則)。

元件聚合張力圖
- REP(複用/釋出等同原則):軟體複用的最小粒度應該等同於其釋出的最小粒度
- CCP(共同閉包原則):將同時修改,目的相同的類放到同一個元件;不會同時修改,目的不同的類放到不同的元件
- CRP(共同複用原則):不要強迫一個元件的使用者依賴他們不需要的東西
這些原則乍看上去是全新的理念,細細品來又好像“新瓶裝舊酒”的老把戲。CCP不就是SRP(單一職能原則)?CRP不就是ISP(介面隔離原則)?REP,等等,這是不言自明的公理呀!難怪有些架構師朋友說,鮑勃大叔老了,又拿著SOLID那一套概念出來忽悠
。
不妨換個思路想想,通常當談論SOLID、高內聚低耦合、穩定依賴、穩定抽象系列原則的時候,我們是處於軟體系統生命週期的哪一環?不出意外,大家都是從編寫原始碼,即開發(Development)的角度出發的。但是,我們又清晰地瞭解,軟體系統的生命週期其實還包含除開發之外的部署、釋出,執行和維護環節。那麼問題來了,在這些環節裡,哪些指導原則是適用的呢?
在跳脫了開發的思維桎梏之後,我們通過兩種手段分析下這三條原則。
分開看
REP原則闡述了一個簡單的道理:軟體複用是基本要求。在追求軟體複用的過程中,逐步形成了標準的釋出流程,如:版本號( ofollow,noindex">語義化版本 ),釋出時間,變更內容等。這要求元件中所包含的模組和類都必須同時可釋出,而可釋出的深層含義既是對使用者的承諾,也是對作者的約束。元件是否向後相容?是否包含破壞性的變更?升級的注意事項?
CCP原則是指儘量把變更頻率相同的模組和類放到同一個元件當中。這樣做的好處是,當相關功能更新時,我們可以把原始碼的變更侷限在某一個元件當中,而不需要橫跨多個元件,從而減少了部署,驗證和釋出的次數。概括來說,這是 區域性化影響 的優勢。CCP和OCP(開閉原則)中強調的“閉包”也有關聯,所謂 封裝可變因素 就是形成閉包的過程,CCP要求將同一時間變更的點聚合起來,達到閉包的效果。
CRP原則是說元件和元件之間的依賴應該達成一種默契——如果不需要完全使用某個元件中所有的模組和類,那麼就不要依賴它。這看上去不太可能,但是有一點意義,它指導我們:不是緊密相連的模組和類不應該被放到同一個元件裡。因為我們知道一旦某個元件變更升級之後,依賴它的元件往往也會被動的變更升級,即便是和自己那些無關的變更也是如此。而每次變更都意味著重新編譯,部署驗證和釋出。
合起看
REP原則說明軟體複用是基礎,複用是通過釋出流程規範的。在複用和釋出的上下文中,CCP原則為了便於後期維護,需要儘可能地將變更頻率相同的模組和類放到相同的複用單元——元件中;CRP原則為了避免頻繁釋出,應該將每個元件分割的足夠小,減少無關變更導致依賴鏈條的連鎖釋出反應。
如果我們只兼顧REP和CCP原則,那麼就可能由於連鎖釋出反應,出現很多不必要的釋出;如果只兼顧REP和CRP原則,那麼就可能因為實現一個功能需要橫跨多個元件修改,造成過多的元件變更;如果只兼顧CCP和CRP,那我們可能就忘記了複用這檔子事兒,這在先前我們批判鮑勃大叔的時候已經體現出來了。
小結
軟體系統的生命週期裡處處充斥著約束條件,每多一個環節往往就會多一種矛盾,進而衍生出多個方向的約束。元件聚合張力圖反映的是釋出和開發之間的矛盾,需要儘量遵循REP,CCP和CRP原則,滿足其約束,才能減少變更成本。
元件構建過程中,除了聚合原則,還有耦合原則——描述的是元件的依賴關係。聚合原則告訴我們的是軟體系統中的最小元素,耦合原則說的是元素之間的關係,當這兩者和系統的功能結合到一起,就構成一個執行著的系統。系統是逐漸演化出來,即便我們熟知REP,CCP和CRP原則,也沒有辦法說,在系統構建之初,遵循這些原則就能畫出完美的元件結構圖。這便是“自頂而下”的設計不靠譜的基本解釋。
“自定而下”的設計不靠譜還有更深層次的原因。本書的第14章“元件耦合”會有答案,且聽下回分解。
於2018-10-28