組合思維可以說是來自于Unix的設(shè)計(jì)哲學(xué):主張組合設(shè)計(jì),而不是單體設(shè)計(jì);主張使用集體智慧,而不是某個(gè)人的特殊智慧。
Unix哲學(xué)發(fā)展至今,誕生了無數(shù)優(yōu)秀的設(shè)計(jì)原則和最佳實(shí)踐。其中,對(duì)于編程來說,最有價(jià)值的原則就是 Peter H. Salus 總結(jié)的三條原則:
- 編寫可以做一件事并且做的很好的程序。
- 編寫程序以協(xié)同工作。
- 編寫程序來處理文本流,因?yàn)檫@是一個(gè)通用接口。
這三條規(guī)則可以理解為:簡單完備性、組合思維和數(shù)據(jù)驅(qū)動(dòng)。
1. 簡單完備性
這其實(shí)就是 “ 簡單原則 ”,其宗旨就是:一個(gè)程序只做一件事,并且做得很好。
這條原則的主要的作用就是能夠極大地減低軟件復(fù)雜度。
1.1 軟件復(fù)雜度
問題來了,什么是軟件復(fù)雜度。
? 軟件復(fù)雜度(區(qū)別于計(jì)算復(fù)雜度)是對(duì)影響軟件內(nèi)部關(guān)聯(lián)關(guān)系的屬性的描述。
? —— Manny Lehman 《軟件演進(jìn)法則》
其實(shí)就是,代碼之間的互相影響越多,軟件就越復(fù)雜。
軟件復(fù)雜度一般來自三方面:
- 代碼庫規(guī)模: 代碼庫規(guī)模越大,通常越復(fù)雜,但代碼行數(shù)和復(fù)雜度并不是正相關(guān)。比如,同樣的類庫, Java 代碼類庫 通常會(huì)比 C++ 類庫的代碼行數(shù)更多,其實(shí)是由于語言特性導(dǎo)致,并不一定更復(fù)雜。
- 技術(shù)復(fù)雜度: 也就是不同的編程語言、服務(wù)架構(gòu)等對(duì)于開發(fā)人員理解的難易度。
- 實(shí)現(xiàn)復(fù)雜度:不同開發(fā),對(duì)于需求理解不同,代碼實(shí)現(xiàn)就不同。
1.2 如何降低代碼復(fù)雜度?
-
代碼庫規(guī)模:減少硬編碼來控制代碼量。 比如,以策略模式替代大量 if-else;使用工具類減少從重復(fù)代碼調(diào)用;語言特性的一些類庫,如 Java 8 的 lambda 表達(dá)式。 -
技術(shù)復(fù)雜度:在設(shè)計(jì)時(shí)做好技術(shù)選型。 簡單來講,系統(tǒng)設(shè)計(jì)時(shí)要確認(rèn)好技術(shù)方案,是否會(huì)引入過于復(fù)雜的組件,或是否存在過渡設(shè)計(jì);確認(rèn)系統(tǒng)設(shè)計(jì)方案的后續(xù)可維護(hù)工作,是否存在過高的學(xué)習(xí)成本等等。 -
實(shí)現(xiàn)復(fù)雜度:使用統(tǒng)一的代碼規(guī)范。 使用同一套編碼規(guī)范,能夠盡量統(tǒng)一不同開發(fā)之間的編程風(fēng)格,減少適應(yīng)代碼風(fēng)格的維護(hù)成本。
2. 組合思維
2.1 為什么需要組合思維?
開發(fā)時(shí),即使在項(xiàng)目前期做了大量的準(zhǔn)備工作,也不能完全比需求的變化,一旦需求發(fā)生變化,往往就意味著代碼要發(fā)生變更。
那么,組合思維就顯得十分重要,把軟件設(shè)計(jì)成獨(dú)立組件并能隨意組合,才能真正應(yīng)對(duì)不斷變化的需求。
2.2 如何做到組合思維?
-
解耦:代碼依賴關(guān)系越多,就越復(fù)雜,只有將代碼不斷拆分,才更容易理解它們之間的關(guān)系。 其實(shí),就是常說的設(shè)計(jì)時(shí)要盡量分離接口與實(shí)現(xiàn),程序應(yīng)耦合在標(biāo)準(zhǔn)和規(guī)范上,而不是耦合在具體代碼實(shí)現(xiàn)邏輯上。 -
模塊化:模塊化的深層含義是可替換的一致性。 比如,想使用 RPC 協(xié)議,可以選擇 Dubbo 、gRPC 等框架,這兩個(gè)框架的基礎(chǔ)是 RPC 協(xié)議,無非只是實(shí)現(xiàn)的組件框架不同,可以互相替換,實(shí)現(xiàn)的功能是一致的。 也就是說,一致性指的是不同框架通過實(shí)現(xiàn)同一個(gè)功能來保持功能的一致性。
上面說了那么多,其實(shí)就是老生暢談的高內(nèi)聚、低耦合,模塊內(nèi)部盡量聚合以保持功能的一致性,模塊外部盡量通過標(biāo)準(zhǔn)來耦合。
簡單來說,通過提供機(jī)制而不是策略,來保證軟件的自由組合,每次需求的修改,僅僅是策略調(diào)整,不需要更改整個(gè)系統(tǒng)機(jī)制。
3. 數(shù)據(jù)思維
目前的互聯(lián)網(wǎng)應(yīng)用中,絕大部分都是數(shù)據(jù)密集型,而不是計(jì)算密集型。
也就是說,設(shè)計(jì)時(shí),做重要的是要徹底了解這個(gè)需求的數(shù)據(jù)是什么:如何組織數(shù)據(jù)結(jié)構(gòu),如何產(chǎn)生數(shù)據(jù)、如何處理數(shù)據(jù)、如何存儲(chǔ)數(shù)據(jù)、如何展示數(shù)據(jù)、如何刪除數(shù)據(jù)。
簡單來說,就是數(shù)據(jù)驅(qū)動(dòng)編程:編程中重要的是數(shù)據(jù)結(jié)構(gòu),而不是算法。
因?yàn)榛叶劝l(fā)布和客戶端程序版本升級(jí)的問題,當(dāng)數(shù)據(jù)結(jié)構(gòu)發(fā)生變化時(shí)(添加數(shù)據(jù)庫字段等),往往會(huì)出現(xiàn)新舊代碼及新舊數(shù)據(jù)格式在線上環(huán)境共存的問題,因此,要考慮數(shù)據(jù)的兼容性。
數(shù)據(jù)驅(qū)動(dòng)編程,意味著需要把代碼和代碼作用的數(shù)據(jù)結(jié)構(gòu)拆分,來達(dá)到改變程序邏輯時(shí),僅需編輯數(shù)據(jù)結(jié)構(gòu),減少代碼修改的目的。
簡單來說,就是設(shè)計(jì)時(shí)需要考慮數(shù)據(jù)本身能支持哪些場景?
是否需要預(yù)留接口功能或抽象相關(guān)模塊,避免一次性代碼的產(chǎn)生,每次需求變更都要出現(xiàn)大量代碼變更,也就是設(shè)計(jì)時(shí)要以解決數(shù)據(jù)變化為中心,而不是僅關(guān)心當(dāng)前需求對(duì)于數(shù)據(jù)的要求。
參考資料: 《趣學(xué)設(shè)計(jì)模式》https://kaiwu.lagou.com/course/courseInfo.htm?courseId=710#/detail/pc?id=6863
|