我們一起聊聊如何判斷架構(gòu)設(shè)計(jì)的優(yōu)劣?
架構(gòu)設(shè)計(jì)的基本準(zhǔn)則是非常重要的,它們指導(dǎo)著我們?nèi)绾螛?gòu)建可靠、可維護(hù)、可測(cè)試的系統(tǒng)。下面是這些準(zhǔn)則的轉(zhuǎn)換表達(dá)方式:
簡(jiǎn)單即美(KISS):KISS原則的核心思想是保持簡(jiǎn)單。在設(shè)計(jì)系統(tǒng)之前,首先要正確理解系統(tǒng)需求,然后才進(jìn)行設(shè)計(jì)。要避免過(guò)度設(shè)計(jì),除非有人能承擔(dān)復(fù)雜性的成本。這里的“簡(jiǎn)單”強(qiáng)調(diào)易實(shí)施性和易理解性。接口應(yīng)該自然地表達(dá)語(yǔ)義,讓人一看方法名就能理解其功能。
模塊化(Modularity):模塊化強(qiáng)調(diào)的是將系統(tǒng)分解成互相獨(dú)立的模塊。從架構(gòu)設(shè)計(jì)的角度來(lái)看,模塊的接口比實(shí)現(xiàn)更為重要。我們應(yīng)該專(zhuān)注于模塊而不是框架,因?yàn)榭蚣苁且鬃兊?,而模塊是更加穩(wěn)定和可復(fù)用的。設(shè)計(jì)模塊時(shí),應(yīng)忽略框架的存在,專(zhuān)注于模塊的接口設(shè)計(jì),并確保接口足夠通用。
可測(cè)試性(Testable):設(shè)計(jì)應(yīng)該以可測(cè)試性為第一目標(biāo)??蓽y(cè)試性通常意味著低耦合,因?yàn)榈婉詈系哪K更容易進(jìn)行單元測(cè)試。模塊測(cè)試的第一步是創(chuàng)建環(huán)境模擬,即模擬模塊所依賴(lài)的其他模塊。測(cè)試能夠幫助我們發(fā)現(xiàn)架構(gòu)調(diào)整的潛在問(wèn)題,并且在代碼重構(gòu)時(shí)尤其重要。
正交分解(Orthogonal Decomposition):正交分解是指對(duì)系統(tǒng)進(jìn)行獨(dú)立且相互無(wú)關(guān)的分解過(guò)程。這個(gè)原則強(qiáng)調(diào)的是乘法而不是加法,即組合而不是繼承。通過(guò)組合相互獨(dú)立、沒(méi)有相關(guān)性的模塊,可以構(gòu)建出我們所需的業(yè)務(wù)場(chǎng)景,而不是通過(guò)繼承疊加能力來(lái)改造模塊。
核心系統(tǒng)的傷害值
正交分解首先涉及確定核心系統(tǒng)和周邊子系統(tǒng)。核心系統(tǒng)是業(yè)務(wù)的最小功能集,而周邊子系統(tǒng)則通過(guò)逐步增加新功能來(lái)擴(kuò)展系統(tǒng)的功能。對(duì)核心系統(tǒng)的變更必須謹(jǐn)慎對(duì)待。如果某個(gè)新功能在早期未被規(guī)劃,后來(lái)又被確定為核心功能,我們必須認(rèn)真評(píng)估其對(duì)現(xiàn)有架構(gòu)的影響。周邊功能方面,我們關(guān)注的是如何降低添加新功能對(duì)核心系統(tǒng)的影響。無(wú)論情況如何,系統(tǒng)都會(huì)因功能增加而變得復(fù)雜。為了減少新功能的負(fù)面影響,相關(guān)代碼應(yīng)盡可能地內(nèi)聚,即使不寫(xiě)入獨(dú)立的模塊中,也要放在獨(dú)立的文件中。這些代碼被視為周邊系統(tǒng)的功能實(shí)現(xiàn)代碼,而不是核心系統(tǒng)的一部分。我們關(guān)注的是周邊功能對(duì)核心系統(tǒng)的影響。為了添加某個(gè)功能,核心系統(tǒng)需要添加相關(guān)代碼。根據(jù)經(jīng)驗(yàn),核心系統(tǒng)為新功能添加的代碼量越少,該功能與核心系統(tǒng)的耦合度就越低。是否可能添加功能而不修改核心系統(tǒng)的代碼?這是可能的,但需要核心系統(tǒng)提供插件機(jī)制。
我們將在后續(xù)討論這個(gè)話(huà)題,現(xiàn)在暫且擱置。讓我們把話(huà)題轉(zhuǎn)回到架構(gòu)設(shè)計(jì)質(zhì)量的評(píng)估上。雖然我們已經(jīng)討論了一些架構(gòu)設(shè)計(jì)的基本準(zhǔn)則,但尚未涉及質(zhì)量評(píng)估的方法。質(zhì)量評(píng)估可以是定性的或定量的。定性評(píng)估方法有一定的數(shù)據(jù)支持,但可能有些主觀。例如,“從某個(gè)角度來(lái)看,我感覺(jué)這個(gè)更好”。定量評(píng)估方法更理想,但目前我個(gè)人尚未聽(tīng)說(shuō)過(guò)任何用于確定架構(gòu)設(shè)計(jì)優(yōu)劣的定量評(píng)估方法。今天我會(huì)介紹一些我個(gè)人想出的判斷公式。這些公式都是經(jīng)驗(yàn)性的,并沒(méi)有經(jīng)過(guò)嚴(yán)格的數(shù)學(xué)證明。假設(shè)一個(gè)架構(gòu)設(shè)計(jì)方案將系統(tǒng)分成了n個(gè)模塊,表示為:[M1, M2, ..., Mn]。其中M1是核心系統(tǒng),其他模塊是周邊子系統(tǒng)。為簡(jiǎn)化起見(jiàn),假設(shè)周邊子系統(tǒng)之間是正交的,相互沒(méi)有耦合。
模塊的耦合度測(cè)量
我們第二個(gè)關(guān)注的問(wèn)題是每個(gè)模塊自身的質(zhì)量,包括模塊接口的質(zhì)量和模塊實(shí)現(xiàn)的質(zhì)量。首先,我們來(lái)看模塊接口的質(zhì)量,這是模塊級(jí)別最重要的部分。模塊接口的質(zhì)量取決于以下兩個(gè)方面:
接口與業(yè)務(wù)的匹配性:接口應(yīng)盡可能自然地反映業(yè)務(wù)需求。然而,從機(jī)器判斷的角度來(lái)看,這一點(diǎn)是無(wú)法計(jì)算的,完全取決于個(gè)人主觀判斷。我們將在下一講“少談框架,多談業(yè)務(wù)”中繼續(xù)探討這個(gè)話(huà)題。
接口的外部依賴(lài):即模塊接口對(duì)外部環(huán)境的耦合程度。下面我們將介紹模塊的“耦合度測(cè)量公式”,它同時(shí)適用于模塊實(shí)現(xiàn)和模塊接口的耦合度測(cè)量。
假設(shè)我們的模塊實(shí)現(xiàn)(或模塊接口)依賴(lài)了模塊A,那么我們的模塊實(shí)現(xiàn)(或模塊里的“符號(hào)”是指被引用的類(lèi)型,包括typedef(類(lèi)型別名)、class或struct,以及被引用的全局變量、全局函數(shù)或成員函數(shù)。
接下來(lái),我們看模塊實(shí)現(xiàn)(或模塊接口)的所有外部依賴(lài),即該模塊的總耦合度公式為其中,耦合度A表示該模塊與依賴(lài)模塊A的耦合程度,如前文所述。而不成熟度系數(shù)A則表示依賴(lài)模塊A的不成熟度程度。若依賴(lài)模塊A完全成熟,不再發(fā)生變化,則為0;若發(fā)生非常劇烈的變動(dòng),規(guī)格甚至無(wú)法確定,則為1。
通過(guò)該耦合度測(cè)量公式,我們鼓勵(lì)依賴(lài)外部成熟模塊。理論上,完全成熟的模塊可能僅限于語(yǔ)言?xún)?nèi)置的數(shù)據(jù)類(lèi)型(如int、string等)。其他模塊則多多少少會(huì)受到一些變化的影響,因此我們應(yīng)盡量減少外部依賴(lài)。
需要注意的是,將模塊接口引用的類(lèi)型A改為object或interface{}類(lèi)型并不能降低耦合度。換句話(huà)說(shuō),如果某參數(shù)為interface,那么這個(gè)interface的耦合度取決于實(shí)際使用時(shí)存在的各種可能類(lèi)型,都會(huì)計(jì)算在依賴(lài)中。
關(guān)于耦合度測(cè)量公式,需要強(qiáng)調(diào)的是,它是一種經(jīng)驗(yàn)公式,僅代表某種價(jià)值主張。在實(shí)際應(yīng)用中,計(jì)算得到的具體耦合度值并沒(méi)有物理意義,只能用于比較兩個(gè)相同功能的系統(tǒng)(或模塊)的架構(gòu)設(shè)計(jì)方案。對(duì)于兩個(gè)功能完全不同的系統(tǒng)(或模塊)A、B,其計(jì)算結(jié)果不能用于評(píng)判彼此的好壞。
首先,我們討論了架構(gòu)設(shè)計(jì)的基本準(zhǔn)則,它們?yōu)槲覀兲峁┝艘粋€(gè)方向。雖然這些準(zhǔn)則不能明確指出何為好與不好,但它們指明了我們?cè)O(shè)計(jì)架構(gòu)的方向。接著,我們開(kāi)始對(duì)架構(gòu)的優(yōu)劣進(jìn)行定性甚至定量的分析。考慮到核心系統(tǒng)的重要性,我們引入了一個(gè)傷害值來(lái)評(píng)估其純潔度。
最后,我們針對(duì)模塊自身的接口或?qū)崿F(xiàn),給出了耦合度測(cè)量公式。通過(guò)這些公式,我們明確了我們的架構(gòu)設(shè)計(jì)的價(jià)值主張。然而,需要意識(shí)到的是,這些并不是全部。判斷模塊間的耦合度是復(fù)雜的。我們的公式在某種程度上只考慮了靜態(tài)依賴(lài)關(guān)系,而沒(méi)有考慮動(dòng)態(tài)依賴(lài)。舉例來(lái)說(shuō),考慮兩個(gè)網(wǎng)絡(luò)模塊A和B,一個(gè)顯而易見(jiàn)的耦合度判斷是:A調(diào)用B的網(wǎng)絡(luò)接口數(shù)量越多,說(shuō)明它們之間的依賴(lài)越大;而A調(diào)用B的網(wǎng)絡(luò)接口的次數(shù)越多,也意味著它們之間的依賴(lài)越大。















 
 
 


















 
 
 
 