免费视频淫片aa毛片_日韩高清在线亚洲专区vr_日韩大片免费观看视频播放_亚洲欧美国产精品完整版

打開APP
userphoto
未登錄

開通VIP,暢享免費電子書等14項超值服

開通VIP
回歸架構(gòu)本真:從規(guī)劃、思維到設(shè)計,構(gòu)建堅不可摧的架構(gòu)根基

一、什么是架構(gòu)

關(guān)于什么是架構(gòu),業(yè)界從來沒有一個統(tǒng)一的定義。Martin Fowler在《企業(yè)應用架構(gòu)模式》中也沒有對其給出定義,只是提到能夠統(tǒng)一的內(nèi)容有兩點:

  1. 最高層次的系統(tǒng)分解;

  2. 系統(tǒng)中不易改變的決定。

《軟件架構(gòu)設(shè)計》一書則將架構(gòu)定義總結(jié)為組成派和決策派:

  • 組成派:架構(gòu)=組件+交互:軟件系統(tǒng)的架構(gòu)將系統(tǒng)描述為計算組件及組件之間的交互。

  • 決策派:架構(gòu)=重要決策集:軟件架構(gòu)是在一些重要方面所作出的決策的集合。

而架構(gòu)的概念最初來源于建筑,因此,我想從建筑的角度去思考這個問題。Wikipedia中,對架構(gòu),即Architecture的定義如下:

Architecture is both the process and the product of planning, designing, and constructing buildings and other physical structures.

簡單翻譯就是:架構(gòu)是規(guī)劃、設(shè)計和構(gòu)建建筑物或其他物理構(gòu)筑物的過程和結(jié)果。

從上面的定義中可知,首先,架構(gòu)的最終目標是為了產(chǎn)出建筑物或其他物理構(gòu)筑物,構(gòu)筑物可以只是一套房子,也可以是一棟樓盤,抑或是一個小區(qū)、商業(yè)區(qū),甚至是一個城市。構(gòu)筑物越大,其架構(gòu)必然也越復雜。

其次,產(chǎn)出建筑物之前需要經(jīng)過三個階段:規(guī)劃(planning)、設(shè)計(designing)和構(gòu)建(constructing)。這三個階段其實也是架構(gòu)的核心了。比如,開發(fā)商要建一個住宅小區(qū),首先肯定要對該小區(qū)有一個整體的規(guī)劃吧:小區(qū)的建設(shè)選址、建設(shè)的規(guī)模、建設(shè)的內(nèi)容、投資估算、建設(shè)周期等等。接著,就要對小區(qū)的各方面進行設(shè)計了,最高層次的應該是小區(qū)的總體布局設(shè)計,拆分開的話就是各樓盤的設(shè)計、綠化的設(shè)計、各種配套設(shè)施的設(shè)計等等,再細化下去就是各種戶型的設(shè)計、樓盤內(nèi)和小區(qū)內(nèi)各種走道的設(shè)計等等。最后,構(gòu)建階段也就是施工階段了,是將之前所有的想法轉(zhuǎn)為實際的建筑物的階段。即架構(gòu)包含了以上的過程和結(jié)果。

那么,如果將建筑物換成了軟件,那就變成對軟件架構(gòu)的定義了:軟件架構(gòu)是規(guī)劃、設(shè)計和構(gòu)建軟件的過程和結(jié)果。

相應地,軟件架構(gòu)的最終目標就是為了產(chǎn)出軟件,可以是一個App,也可以是一個平臺,如SaaS、PaaS、BaaS等等,甚至還可以是智慧城市這樣龐大的生態(tài)系統(tǒng),地球人都知道,越龐大復雜的系統(tǒng),架構(gòu)越難。規(guī)劃階段更多考慮的是軟件的需求,包括業(yè)務(wù)上功能性需求和技術(shù)上的非功能性需求,如可靠性、可擴展性、可維護性等;此階段的架構(gòu)一般為系統(tǒng)架構(gòu)。設(shè)計階段的工作更多的就是拆分細化,以滿足各種需求;此階段的架構(gòu)一般為邏輯架構(gòu)。構(gòu)建階段主要就是對軟件的實現(xiàn)和部署了;此階段的架構(gòu)一般為物理架構(gòu)。

二、架構(gòu)規(guī)劃

架構(gòu)規(guī)劃做什么呢?我覺得主要是規(guī)劃好下個階段架構(gòu)設(shè)計的邊界。而影響架構(gòu)邊界的,其實就是需求。需求形成了對架構(gòu)的約束條件,從而也對架構(gòu)設(shè)計形成了邊界。可以分為三大類:商業(yè)需求、功能需求和質(zhì)量需求。

(一)商業(yè)需求

商業(yè)需求是最高層次的需求,對其含義,我比較贊同溫昱在《軟件架構(gòu)設(shè)計》中提到的解釋:它關(guān)注從客戶群、企業(yè)現(xiàn)狀、未來發(fā)展、預算、立項、開發(fā)、運營、維護在內(nèi)的整個軟件生命周期涉及的商業(yè)因素,包括了商業(yè)層面的目標、期望和限制等。商業(yè)需求一般對架構(gòu)的影響比較大,對架構(gòu)產(chǎn)生限制的商業(yè)因素也比較多,在此列舉一些比較常見的:

  1. 上市時間:上市時間限定了系統(tǒng)從設(shè)計、開發(fā)、測試到上市的時間邊界。之前我跟進過一個垂直于大學生市場的應用,上市時間就要求在新生入學前,不然就會錯過推廣的最佳時期,預留給開發(fā)的時間只有兩個月。因此,我們只好大部分重用前個項目的元素,包括重用服務(wù)端的一些模塊,還包括客戶端的架構(gòu)和界面。當然,一般情況下,預留給開發(fā)的時間不會這么短,但也不會特別長。架構(gòu)師需要根據(jù)時間長短,平衡各方面需求,做好架構(gòu)選型。

  2. 成本預算:成本預算就限定了能使用的資源邊界。不同架構(gòu)的開發(fā)成本肯定不同,要滿足更多功能需求和更多質(zhì)量需求的架構(gòu)成本也更高,在預算有限的情況下,只能權(quán)衡各種需求,優(yōu)先滿足重要程度高的需求。

  3. 人力現(xiàn)狀:100人的開發(fā)團隊和10人的開發(fā)團隊,軟件的架構(gòu)會有很大不同。另外,開發(fā)團隊人員所掌握的技術(shù)也會對架構(gòu)選型有影響。例如,團隊里還沒有人會用React Native,那現(xiàn)階段就不適合選擇React Native作為App架構(gòu)的技術(shù)基礎(chǔ)。

  4. 與外圍系統(tǒng)的集成:當需要與外圍系統(tǒng)集成時,需要認真考慮集成方法,尤其是外圍系統(tǒng)比較老的時候,集成難度可能更高。另外,外圍系統(tǒng)的不可控因素一般也比較多,因此,對架構(gòu)處理這些不可控風險的要求相對也高。

  5. 開放性:封閉的私有系統(tǒng)和開放式系統(tǒng)對架構(gòu)的要求也不同,一個系統(tǒng)如果選擇了開放,那對架構(gòu)的質(zhì)量要求更高,對安全性、擴展性、性能等質(zhì)量屬性都應該比封閉時高。

  6. 目標市場:目標用戶10萬、100萬、1000萬,不同級別的目標市場,架構(gòu)也是大有不同。另外,大眾市場和垂直的專門市場,架構(gòu)也同樣有區(qū)別,較大的專門市場一般都采用產(chǎn)品線的規(guī)劃方案。

  7. 多端支持:現(xiàn)在移動端普遍支持Android、iOS、Wechat,管理端通常則支持PC Web,如果管理端也要支持Android、iOS、Wechat,或者移動端和管理端還要再支持WindowsPhone、黑莓,甚至再支持VR,則需要投入更多時間和人力,架構(gòu)上相應也需要做出調(diào)整。

  8. 期望的系統(tǒng)生存期:從主觀上說,誰都希望自己的系統(tǒng)可以生存很久,但生存期越長,意味著系統(tǒng)的可修改性、可擴展性、可移植性等需要更高。但是,受上市時間、成本預算等因素的制約,再加上軟件本身的變化快,所以,客觀上,一般也不會期望其生存期太長。當系統(tǒng)不能滿足漸增的需求時,基本通過重構(gòu)來解決。

  9. 階段性計劃:每一個大平臺系統(tǒng)普遍都是分階段完成的,因此,前期階段的架構(gòu)設(shè)計時就需要考慮好重用性、擴展性、伸縮性、移植性等特性。但因為每個階段經(jīng)過市場驗證后,需求有可能會變化,所以又不能過度設(shè)計,否則就會造成設(shè)計浪費,還可能加大了后續(xù)階段架構(gòu)調(diào)整的難度。

  10. 國際化:如果走國際化路線,那架構(gòu)上就要考慮好對多國語言的支持。

  11. 競爭對手:產(chǎn)品要比競爭對手優(yōu)秀,那就要在一些關(guān)鍵的功能或質(zhì)量上超越對方,也意味著在這些方面的架構(gòu)需要投入更多。

  12. 法律法規(guī):比如,對某些關(guān)鍵字要進行過濾屏蔽,這是天朝獨有的,大家懂的。

商業(yè)需求多種多樣,有些需求還可能會相互矛盾,比如,上市時間和成本預算就會和期望的系統(tǒng)生存期可能產(chǎn)生矛盾,期望的生存期越長其成本就會越高,需要投入的時間就會越多,那么,就有可能拖延上市時間。因此,做架構(gòu)規(guī)劃時,必須梳理清楚哪些需求是能夠被滿足的,能被滿足的程度如何,需要在各個需求間權(quán)衡利弊。另外,商業(yè)需求因為是最高層次的需求,因此,相對于功能需求和質(zhì)量需求,其優(yōu)先級一般也比較高。

(二)功能需求

功能需求描述了系統(tǒng)應該提供的服務(wù),包括為用戶提供的服務(wù),也包括為其他系統(tǒng)提供的服務(wù)。而架構(gòu)主要就是為功能服務(wù)的,而功能需求基本與具體的業(yè)務(wù)相關(guān)。因此,要做好功能需求這塊的架構(gòu),就必須對該業(yè)務(wù)領(lǐng)域足夠了解,這樣才能更好地抽象建模。對功能需求的架構(gòu)規(guī)劃,主要就是建立業(yè)務(wù)領(lǐng)域模型。領(lǐng)域模型定下來后,下個階段的設(shè)計必須與領(lǐng)域模型保持一致。

而對功能需求進行領(lǐng)域建模之前,還需先梳理下需求的優(yōu)先級。因為受商業(yè)需求的影響,功能需求也需要權(quán)衡。比如,上市時間緊、成本預算低、人力資源也不是很充足的情況下,功能需求只能少不能多。而需要與外圍系統(tǒng)集成的時候,也意味著這部分功能不需要自己實現(xiàn)了;但是,如果外圍系統(tǒng)無法完全滿足需求時,則還需要自己再實現(xiàn)缺失的需求。因此,現(xiàn)階段需要滿足哪些功能需求?需要滿足到什么程度?這兩個問題確定了之后才能更有效地進行領(lǐng)域建模。

領(lǐng)域建模主要就是要分析清楚每個領(lǐng)域模型和模型之間的關(guān)系。還是直接用一個例子來說明吧。假設(shè)現(xiàn)在要做一個支持O2O(Online To Offline)的電商平臺,以下是經(jīng)過梳理后的幾個關(guān)鍵的功能需求:

  1. 商家可以在平臺發(fā)布商品,可以是實體類商品,也可以是服務(wù)類商品。

  2. 實體類商品支持快遞,服務(wù)類商品只能到商家門店兌換消費。

  3. 用戶購買實體類商品時需提供收貨信息。

  4. 用戶購買每個商品時對應生成一個訂單。

  5. 用戶購買的是實體類商品時,可以查看商品的物流信息。

  6. 用戶購買的是服務(wù)類商品時,可以用訂單的兌換碼到商家門店兌換消費。

根據(jù)以上需求,可以初步得到相關(guān)的領(lǐng)域概念有:商家、商品、實體類商品、服務(wù)類商品、物流信息、門店、用戶、收貨信息、訂單、兌換信息。理清這些領(lǐng)域概念之間的關(guān)系之后,可以得到類似于下面的領(lǐng)域模型視圖:

當然,這只是一個很小的例子,實際上的領(lǐng)域模型會比這個例子復雜得多。領(lǐng)域模型確定之后,系統(tǒng)中有多少業(yè)務(wù)領(lǐng)域、各領(lǐng)域概念之間的關(guān)系如何就一清二楚了。

(三)質(zhì)量需求

質(zhì)量需求是三類需求中,需求層次最低的,但卻是大部分架構(gòu)師最關(guān)注的??v覽那么多架構(gòu)技術(shù),就會發(fā)現(xiàn),大部分都是為了解決某個或某些質(zhì)量屬性優(yōu)化的問題。

質(zhì)量屬性常見的有以下這些:

  • 性能(Performance):性能無疑是一個非常重要的特性,尤其在計算資源有限的情況下。但也無需過分追求高性能,從而犧牲其他更重要的特性。

  • 安全性(Security):安全性一般會和性能相互制約,最明顯的例子就是HTTPS,使用HTTPS提高了安全性,但性能就會有所犧牲。很難做到既滿足高安全又高性能,因此需要根據(jù)具體需求平衡兩方面的特性。

  • 可用性(Availability):也有人稱為有效性,一般定義為:可用性 = 系統(tǒng)正常工作時間 / (系統(tǒng)正常工作時間 + 故障維修時間)。此定義就說明了可用性與系統(tǒng)故障有關(guān),故障率高,可用性就低,故障率低,可用性才高。另外,高可用性還說明了系統(tǒng)對故障維修的時間也很短。

  • 易用性(Usability):易用性很容易和可用性混淆,可用性關(guān)注的是系統(tǒng)長時間無故障運行的能力,而易用性關(guān)注的則是系統(tǒng)易于使用的能力。

  • 魯棒性(Robustness):也稱為健壯性、容錯性,是指系統(tǒng)在出現(xiàn)了用戶非法操作、或軟硬件的缺陷導致的異常情況下,系統(tǒng)依然能夠正常運行的能力。比如說,系統(tǒng)在輸入錯誤、磁盤故障、網(wǎng)絡(luò)過載或有意攻擊情況下,能否不死機、不崩潰,就是該軟件的魯棒性。

  • 可伸縮性(Scalability):可伸縮性是指當用戶量和數(shù)據(jù)量增加時,系統(tǒng)維持高服務(wù)質(zhì)量的能力。比如,當并發(fā)量為1W時,系統(tǒng)響應時間為1秒,那如果并發(fā)量增加到100W時,只要通過增加服務(wù)器數(shù)量,而無需對代碼進行修改即可達到系統(tǒng)響應時間依然為1秒,就說明該系統(tǒng)的可伸縮性高。

  • 互操作性(Interoperability):互操作性反映了本系統(tǒng)與其他系統(tǒng)交換數(shù)據(jù)和服務(wù)的難易程度。

  • 可擴展性(Extensibility):也稱為靈活性,反映了系統(tǒng)應對變化的能力。在軟件開發(fā)過程中,需求變更是常有的事,尤其在移動互聯(lián)網(wǎng)時代,變化是非常頻繁的,也因此,可擴展性是移動互聯(lián)網(wǎng)產(chǎn)品重點考慮的質(zhì)量需求。

  • 可理解性(Understandability):可理解性是指開發(fā)人員通過源代碼和相關(guān)文檔,了解程序功能、結(jié)構(gòu)和運行方式的難易程度。遵從好的開發(fā)規(guī)范一般都可以提高可理解性。另外,單一職責原則運用得好,也能大大提高可理解性,所謂“簡單就是美”,簡單才容易理解。

  • 可測試性(Testability):簡單點說,可測試性就是測試和診斷軟件錯誤的難易程度。比如進行單元測試的難易程度。如果程序包含了復雜的處理邏輯、數(shù)據(jù)結(jié)構(gòu)、模塊關(guān)系,可測試性的設(shè)計更顯得尤為重要。

  • 可復用性(Reusability):可重用性表明了一個軟件組件可以在其他程序中使用的難易程度。一般需要將一個組件抽離成通用性的組件時,對可復用性的要求就會比較高。

  • 可移植性(Portability):可移植性表明了將軟件系統(tǒng)從一個運行環(huán)境轉(zhuǎn)移到另一個不同的運行環(huán)境的難易程度。

  • 可維護性(Maintainability):可維護性是指理解、改正、改動、改進軟件的難易程度。我覺得,可維護性是保證一個軟件系統(tǒng)能夠長期生存的最重要的特性,沒有之一。對一個可維護性差的系統(tǒng),久而久之,不斷變得牽一發(fā)而動全身,變得不可維護,慢慢只能宣布滅亡。

理想情況下,誰都希望所有屬性都是高質(zhì)量的,但誰都清楚這是不可能的事。要提高更多質(zhì)量屬性,實現(xiàn)的難度更大,需要付出的成本更高。而且,不同質(zhì)量屬性之間還存在制約關(guān)系,比如,提高安全性,一般就會減低性能;提高了性能,還可能減低了可維護性。因此,在實際做架構(gòu)規(guī)劃時,必須根據(jù)具體需求在各質(zhì)量屬性間權(quán)衡優(yōu)先級。

三、架構(gòu)思維

這里說的架構(gòu)思維是指進行架構(gòu)設(shè)計時最高層級的思考方式,比如:面向過程、面向?qū)ο?、面向切面、面向服?wù)等。

1、面向過程(Procedure Oriented)

面向過程的設(shè)計思路就是將問題分解成一個個步驟,按照步驟一步步執(zhí)行之后,問題就解決了。每一個步驟就是一個子過程,也可以稱為一個模塊,子過程還可以繼續(xù)拆分成更多更細的子過程。因此,面向過程的設(shè)計核心就是過程分析、功能分解,一般采用自頂向下、逐步求精的分解方式。一個大的程序可以分解成多個子程序,子程序再分解成多個大模塊,大模塊再分解成多個小模塊,最終分解成一個個函數(shù)。

在此我想借用一個象棋對戰(zhàn)的例子,例子來源于一篇很老的文章:架構(gòu)師之路(4)---詳解面向?qū)ο?。以下是采用面向過程的設(shè)計思路分解的對戰(zhàn)流程圖:

將以上每個流程分別用函數(shù)實現(xiàn),問題就解決了。

面向過程的優(yōu)點主要有兩個:一是流程清晰簡單;二是性能比較高。尤其是性能,這也是為什么至今很多單片機開發(fā)、驅(qū)動程序開發(fā)、或其他與硬件相關(guān)的系統(tǒng)開發(fā)等對性能要求很高的軟硬件程序依然在用面向過程的方式進行設(shè)計和開發(fā)。

面向過程的缺點也很明顯:一是主程序太重,主程序與模塊承擔的任務(wù)不均衡;二是函數(shù)不易擴展,導致其可擴展性、可復用性、可維護性相對都比較差;三是上下層級模塊之間的聯(lián)系太緊密,耦合高,所以模塊也難以復用。

2、面向?qū)ο?Object Oriented)

面向過程的思路是“怎么做”,關(guān)注于實現(xiàn)細節(jié);而面向?qū)ο蟮乃悸肥恰罢l來做”,關(guān)注于抽象的對象。對象的封裝、繼承和多態(tài)等特性,讓我們以更接近現(xiàn)實世界的方式來思考程序設(shè)計。面向?qū)ο笙啾让嫦蜻^程容易實現(xiàn)更好的分離,相應地可擴展性、可復用性、可維護性也會比較高,但同時會犧牲掉一些性能。不過,也因為硬件發(fā)展迅猛,所以犧牲的那點性能也不算什么了。

面向?qū)ο笤O(shè)計的難點在于抽象,從問題域中抽象出一個個對象,并找出它們之間的關(guān)系。好在有SOLID原則和一大堆設(shè)計模式指導我們?nèi)绾胃玫卦O(shè)計。也有領(lǐng)域驅(qū)動設(shè)計的方法論指導我們怎么進行領(lǐng)域建模。

還是象棋對戰(zhàn)的例子,用面向?qū)ο蟮脑O(shè)計思路,可以抽象出以下三種對象:

  • 棋手:負責行棋,紅黑兩方行為一致。

  • 棋盤:負責繪制棋盤畫面。

  • 裁判:負責判定吃子、犯規(guī)和輸贏等。

三者關(guān)系如下圖:

棋手對象行棋后,棋盤對象根據(jù)棋子布局的變化刷新棋盤畫面,裁判對象則對棋局進行判定。

3、面向切面(Aspect Oriented)

面向切面,也就是AOP,是對面向?qū)ο蟮囊环N擴展,為了彌補面向?qū)ο蟮木窒扌浴?/strong>面向?qū)ο笤O(shè)計主要是對業(yè)務(wù)領(lǐng)域進行抽象封裝,但對于業(yè)務(wù)領(lǐng)域之外的內(nèi)容,比如日志記錄、權(quán)限檢查、事務(wù)支持等,在沒有AOP之前,只能將實現(xiàn)這些功能的代碼散布在所有對象層次中,但這些代碼與所散布的對象的核心業(yè)務(wù)功能是沒任何關(guān)系的。這種做法也導致了大量重復的代碼,而且難以復用。AOP就是為了解決這種問題而產(chǎn)生的,將這些與業(yè)務(wù)領(lǐng)域無關(guān)的部分分離出來,以橫切面的方式注入系統(tǒng),從而減少重復代碼、減低耦合度、增強擴展性和維護性。

將日志記錄、權(quán)限檢查、事務(wù)支持等等使用橫切技術(shù)分別獨立成一個個服務(wù)模塊,這些模塊也稱為“橫切面”,這樣就可以將這些與業(yè)務(wù)無關(guān)的服務(wù)從業(yè)務(wù)核心中解耦出來,就可以將系統(tǒng)劃分為兩部分:業(yè)務(wù)核心和通用服務(wù)。業(yè)務(wù)核心依然采用面向?qū)ο蟮乃悸啡ピO(shè)計,而通用服務(wù)則可以采用面向切面的思想來實現(xiàn)。

Spring就大量使用了AOP技術(shù),OkHttp的Interceptor也是AOP設(shè)計的一種實現(xiàn)。很多場景都可以使用AOP的思想去設(shè)計,比如添加統(tǒng)一的Http Request Header,添加統(tǒng)一的登錄驗證,添加統(tǒng)一的緩存,添加統(tǒng)一的錯誤處理,等等,只要是通用的功能點基本都可以使用AOP的思想去設(shè)計和實現(xiàn)。

4、面向服務(wù)(Service Oriented)

不管是SOA還是現(xiàn)在流行的微服務(wù)架構(gòu),都是采用面向服務(wù)的思維方式。說到面向服務(wù),需要先了解一個概念:Monolith,也稱為單體架構(gòu)。在沒有SOA思想之前,軟件系統(tǒng)將所有功能整合成一個獨立的軟件包,然后部署在單一的平臺上。比如,在J2EE平臺,一個軟件系統(tǒng)最終會打成一個包含所有功能的WAR包,然后部署到Web容器中。若要擴展的話,則通過復制這個WAR包部署到多個Web容器來實現(xiàn)。這種方式,如果程序需要改動,不管多么微小的改動,都需要重新打包個新的WAR包,并替換掉所有Web容器的舊WAR包。

面向服務(wù)的架構(gòu)思想則是,將系統(tǒng)的不同功能分離成一個個單獨的應用程序或組件,統(tǒng)稱為服務(wù),不同服務(wù)部署在不同容器中,不同服務(wù)之間通過一些輕量級的交互機制來通信,如HTTP,RPC等。這樣,相比單體架構(gòu),功能服務(wù)之間明顯是松耦合的,擴展也會靈活很多。而且,不同服務(wù)還可以用不同編程語言實現(xiàn),部署到不同平臺。

不管是面向過程,面向?qū)ο?,面向切面,還是面向服務(wù),最本質(zhì)的區(qū)別還是在于看問題的角度不同。而在實際應用中,也不會只使用一種架構(gòu)思維,而是綜合考慮的,系統(tǒng)的不同方面或不同層級可能會用不同的架構(gòu)思維去思考。比如,一個龐大的復雜系統(tǒng),整體上可能用面向服務(wù)的架構(gòu)思維去拆解各種服務(wù),業(yè)務(wù)核心方面的服務(wù)可能再用面向?qū)ο蟮募軜?gòu)思維進行建模,通用功能服務(wù)還是用面向切面的架構(gòu)思維來設(shè)計,事務(wù)流程當然是采用面向過程的架構(gòu)思維最直觀。

四、架構(gòu)原則

架構(gòu)思維從面向過程,到現(xiàn)在的面向服務(wù),以后也不知道還會出現(xiàn)什么新的思維方式。但無論是何種思維方式,都存在一些共通性的架構(gòu)原則,可以指導我們?nèi)绾卧O(shè)計出一個合適的架構(gòu)。從另一方面來說,架構(gòu)設(shè)計,不管是面向過程、面向?qū)ο?、面向切面,還是面向服務(wù),無一例外,主要都是在對復雜的系統(tǒng)進行分解。那么,相應地,就需要思考三個問題:分解為哪些?如何分解?分解到什么程度?相對應地,有三個重要原則可以分別為解答這三個問題提供指引。

1、關(guān)注點分離原則

關(guān)注點分離原則主要就是為了解決將復雜系統(tǒng)分解為哪些部分的問題,分解出來的部分就是關(guān)注點。過程、對象、切面、服務(wù),只是分解的角度(也是關(guān)注點)不同而已。將復雜的問題根據(jù)不同的關(guān)注點分解為多個相對簡單的問題,再對每個簡單的問題進行分別處理,這就是關(guān)注點分離。分離之后,各個關(guān)注點相對獨立,每個關(guān)注點的變化基本不會影響到其他的關(guān)注點,即使需要改變,改變的部分也很小。需要擴展時,影響也將會最小化。

關(guān)注點分離,最難的在于如何識別出有哪些關(guān)注點。要識別出有哪些關(guān)注點,需要將復雜系統(tǒng)不同的方方面面抽象成一個個具有清晰明確的邊界的概念模型,或為“對象”,或為“組件”,或“切面”,或“服務(wù)”,以將復雜問題分解為一個個相對簡單的問題。

從不同維度,可以有不同的分離方案。除了上面提到的面向過程、面向?qū)ο?、面向切面、面向服?wù)等思維角度之外,還有如下圖所示的其他幾種不同維度,該圖引自《軟件架構(gòu)設(shè)計》一書中的【2.1.1 關(guān)注點分離之道】一節(jié):

上圖分別從功能職責、通用性、大小粒度的不同維度進行分離。從職責維度進行分離,就可以分為三層架構(gòu):展現(xiàn)層、業(yè)務(wù)層、數(shù)據(jù)層,相應的關(guān)注點就是:數(shù)據(jù)展示、數(shù)據(jù)加工、數(shù)據(jù)管理。另外,數(shù)據(jù)層還可以再分離為網(wǎng)絡(luò)層和緩存層。從通用性維度來看,就可以分離出技術(shù)通用部分、領(lǐng)域通用部分、特定應用部分。一般,使用框架技術(shù)就可以用于分離各種不同的通用部分。從大小粒度的維度考慮,無非就是將復雜系統(tǒng)分離為各個子系統(tǒng),再分離為不同模塊,再細分到不同類。

在實際應用中,并不會只采用一種維度,而是多種維度綜合考慮,不同部分采用不同維度的分離方案。比如,也許,整體上按職責分離為多層架構(gòu),然后,在某些層級根據(jù)大小粒度再進行分離,例如將業(yè)務(wù)層按照不同業(yè)務(wù)模塊進行分離。另外,也會將不同的通用部分進行分離,例如可將技術(shù)通用部分的日志記錄、領(lǐng)域通用部分的權(quán)限檢查分別分離出來。

2、高內(nèi)聚低耦合原則

系統(tǒng)應該如何分解?或者說關(guān)注點應該如何分離?高內(nèi)聚低耦合原則就可以為該問題提供設(shè)計指引。

內(nèi)聚是指模塊內(nèi)部的功能和元素之間的緊密程度,而耦合則是指模塊與模塊之間的關(guān)聯(lián)程度。

內(nèi)聚可分為好多種:功能內(nèi)聚、順序內(nèi)聚、通信內(nèi)聚、過程內(nèi)聚、時間內(nèi)聚、邏輯內(nèi)聚、偶然內(nèi)聚。功能內(nèi)聚是最強最好的內(nèi)聚,模塊內(nèi)各元素共同協(xié)作完成一個單一的功能,這些元素緊密聯(lián)系、缺一不可。順序內(nèi)聚則是指,模塊中各個處理元素和同一個功能密切相關(guān),而且這些處理必須順序執(zhí)行,通常前一個處理元素的輸出時后一個處理元素的輸入。順序內(nèi)聚的內(nèi)聚度也比較高,但相比功能內(nèi)聚,缺點就是可維護性相對差些。偶然內(nèi)聚則是最弱的內(nèi)聚,模塊內(nèi)的各元素之間沒有任何聯(lián)系,只是偶然地被湊到一起。

耦合也分為好多種:非直接耦合、數(shù)據(jù)耦合、標記耦合、控制耦合、外部耦合、公共耦合、內(nèi)容耦合。非直接耦合表示兩個模塊直接沒有直接關(guān)系,它們之間的聯(lián)系完全是通過主模塊的控制和調(diào)用來實現(xiàn)的,其耦合度是最弱的,模塊獨立性最強。數(shù)據(jù)耦合表示調(diào)用模塊和被調(diào)用模塊之間只傳遞簡單的數(shù)據(jù)項參數(shù),相當于高級語言中的值傳遞。標記耦合也稱為特征耦合,表示調(diào)用模塊和被調(diào)用模塊之間傳遞的不是簡單數(shù)據(jù),而是數(shù)據(jù)結(jié)構(gòu),像高級語言中的數(shù)據(jù)名、記錄名和文件名等數(shù)據(jù)結(jié)果,這些名字即為標記,其實傳遞的是地址??刂岂詈蟿t表示模塊之間傳遞的不是數(shù)據(jù)信息,而是控制信息例如標志、開關(guān)等,一個模塊控制了另一個模塊的功能。外部耦合則是指一組模塊都訪問同一全局簡單變量,而且不通過參數(shù)表傳遞該全局變量的信息。內(nèi)容耦合則是一個模塊直接訪問另一模塊的內(nèi)容,這是最強的耦合。

  • 高內(nèi)聚的設(shè)計原則是說:一個模塊只完成一個單一的功能,盡可能使模塊達到功能內(nèi)聚。

  • 低耦合的設(shè)計原則是說:若模塊間必須存在耦合,應盡量使用數(shù)據(jù)耦合,少用控制耦合,慎用或有控制地使用公共耦合,并限制公共耦合的范圍,盡量避免內(nèi)容耦合。

3、適度設(shè)計

適度設(shè)計原則關(guān)注的就是系統(tǒng)分解到什么程度的問題。適度設(shè)計就是指設(shè)計不要過度,也不要不足。那么,怎樣才算設(shè)計過度?怎樣才算設(shè)計不足?一句話,設(shè)計過度就是想太多,設(shè)計不足就是想太少。感覺好虛,是吧?我也這么覺得。因為,如何判斷一個設(shè)計是否過度或不足,并沒有標準的可量化指標。因此,設(shè)計是否適度,更多在于主觀的判斷。而如何避免設(shè)計過度或不足,更多的也在于個人經(jīng)驗積累所形成的直覺。

設(shè)計不足相對還比較容易判斷,導致設(shè)計不足的原因主要有兩個:一是因為新手的設(shè)計經(jīng)驗不足而導致;二是因為一味追求快速實現(xiàn)產(chǎn)品功能而跳過或大幅度減少了設(shè)計而導致。

也有些設(shè)計過度比較明顯的例子,比如Uncle Bob提出的Clean架構(gòu),每個關(guān)注點都有著清晰明確的邊界,架構(gòu)真的很清晰,可維護性、可測試性都非常不錯,高內(nèi)聚低耦合。但是,如果將其應用到一個只有兩三個開發(fā)人員的小團隊的小項目中,就會明顯發(fā)現(xiàn)代碼量大而且復雜,每需要添加一個小功能,卻需要編寫大量代碼。這對一個小團隊小項目來說,明顯不適合。Clean架構(gòu)比較適用于人員較多的團隊,和中大型項目。

因此,判斷設(shè)計是否適度,不能脫離團隊和項目的現(xiàn)狀。另外,還有其他現(xiàn)狀因素,包括各種商業(yè)需求、功能需求和質(zhì)量需求。大部分情況下,形成過度設(shè)計的原因在于:一是過多地考慮了未來可能發(fā)生的變化;二是為了追求設(shè)計而設(shè)計。適度設(shè)計,首先應該著眼于當下,當下的需求、當下的開發(fā)成本、當下的人員和項目現(xiàn)狀;其次才是適當考慮如何應對未來的變化。對于未來的變化,也不是任何可能都要考慮,只需考慮在可預見的未來里有非常大的幾率會發(fā)生的變化即可,這個非常大的幾率可以達到90%以上。比如,已經(jīng)確定要實現(xiàn)的需求,只是因為優(yōu)先級問題而稍微延后;比如,已經(jīng)確定的人員擴充計劃;比如,雙11要搞活動,交易量將會激增;等等。

也就是說,適度設(shè)計的原則,可以總結(jié)為:設(shè)計應該優(yōu)先滿足當前確定的需求,再滿足可預見未來里幾乎可以確定會發(fā)生的需求。只滿足當前需求而不考慮未來,就容易導致設(shè)計不足;而過多地考慮未來可能發(fā)生的需求,就容易導致設(shè)計過度。因此,適度設(shè)計需要在當前需求和未來需求之間做好平衡,而我覺得只考慮當前需求和未來幾乎確定會發(fā)生的需求是最好的平衡點。

作者介紹 李紀鋼

本站僅提供存儲服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊舉報。
打開APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
生活服務(wù)
分享 收藏 導長圖 關(guān)注 下載文章
綁定賬號成功
后續(xù)可登錄賬號暢享VIP特權(quán)!
如果VIP功能使用有故障,
可點擊這里聯(lián)系客服!

聯(lián)系客服