第五部分 軟件架構(gòu)
什么是軟件架構(gòu)?軟件架構(gòu)工作本質(zhì)上是在回答一個關于“如何將系統(tǒng)切分成組件,并且處理好各組件之間的關系”的問題。一個優(yōu)秀的架構(gòu)師應該允許系統(tǒng)盡可能推遲與實現(xiàn)細節(jié)相關的決策。要設計一個好的軟件架構(gòu),除了要使系統(tǒng)用例的正常運行,還要同時考慮系統(tǒng)的維護、開發(fā)以及部署等非需求因素。
那么為了盡可能地將一些與系統(tǒng)核心業(yè)務邏輯無關的決策延后,我們就必須劃分好軟件架構(gòu)中的清晰邊界。比如業(yè)務邏輯和數(shù)據(jù)庫之間就應該有一條邊界線,因為你是具體使用Oracle還是MySQL作為數(shù)據(jù)庫,都不應該影響核心業(yè)務邏輯。同理,用戶界面也與業(yè)務邏輯無關,所以這兩者之間也應該有一條清晰的邊界線。因為具體使用的是命令行界面還是使用網(wǎng)頁等UI方式來呈現(xiàn),本質(zhì)上都與核心業(yè)務不是緊密相關的。在具體的架構(gòu)實踐當中,有一種叫做插件式架構(gòu)的方式廣為流傳,其理念就是將核心業(yè)務邏輯和其他組件(作為外部插件)進行隔離開來。
一旦邊界劃分完畢之后我們就得進一步思考如何處理跨邊界的調(diào)用,最簡單的跨邊界調(diào)用方式就是用低層客戶端來直接調(diào)用高層服務函數(shù),這在單體架構(gòu)當中十分普遍。我們這里所說的高層和低層組件,其實是按照輸入與輸出之間的距離來進行定義的,通常來說它距離系統(tǒng)的輸入或者輸出越遠,它所處的層次就越高,而能夠直接管理輸入輸出的策略,在系統(tǒng)當中就是屬于低層的。拿操作系統(tǒng)來舉例,低層的組件就是那些管理磁盤的程序,而高層的組件就是依賴磁盤管理程序的文件管理系統(tǒng)。由于低層的組件通常來說比較容易頻繁變更,而高層組件相對來說較為穩(wěn)定,因此我們需要將低層組件隔離開來,并且將依賴關系都統(tǒng)一調(diào)整為指向高層策略。低層次組件要跨越邊界到達高層組件,這個數(shù)據(jù)流是自下而上的。所以一旦我們需要使高層組件能夠調(diào)用低層組件,就需要運用動態(tài)技術來反轉(zhuǎn)依賴關系,比如使用動態(tài)鏈接庫。對于我們常見的Main組件應該是整個系統(tǒng)中的一個底層組件,它處于整潔架構(gòu)的最外圈,負責加載系統(tǒng)信息,然后將控制權(quán)轉(zhuǎn)回到系統(tǒng)的高層組件。
要實現(xiàn)跨越邊界的調(diào)用,除了直接的函數(shù)調(diào)用外,我們還可以引入線程,進程以及服務的方式。
我們在軟件架構(gòu)當中還經(jīng)常提到的一個概念是業(yè)務邏輯,那么對于一個軟件來說,其最核心的業(yè)務邏輯是什么呢?它本質(zhì)上就是系統(tǒng)軟件系統(tǒng)中那些能夠真正產(chǎn)生商業(yè)價值的邏輯和過程,無論它是否是以計算機軟件的方式進行實現(xiàn)的,它的作用和邏輯都應該是相同的。因此我們通常會將這些關鍵的業(yè)務邏輯出現(xiàn)成一個業(yè)務實體,并且作為高層組件,至于底層的具體實現(xiàn)則交由低層組件來完成。
在很多設計不佳的軟件里,你經(jīng)常會看到業(yè)務邏輯和數(shù)據(jù)庫以及用戶界面等邏輯相耦合,這樣隨著時間的推移,軟件的可維護性和代碼質(zhì)量都很難得到保障。
一個系統(tǒng)的架構(gòu)應該著重于對于系統(tǒng),用例本身的設計,而應該盡量避免強依賴于系統(tǒng)所使用的框架。

跨越邊界的數(shù)據(jù),應該保持數(shù)據(jù)結(jié)構(gòu)的簡單,而且不應該違反依賴規(guī)則。
在系統(tǒng)架構(gòu)的邊界處,可以使用謙卑對象模式,這種模式可以很好的提高系統(tǒng)的可測試性。一個很好的例子就是對于GUI的實現(xiàn),我們可以將其分為展示器和系統(tǒng)視圖兩個部分。其中視圖部分屬于謙卑對象,該對象只負責將數(shù)據(jù)填充到 GUI上。而另一部分是展示器對象,它負責從應用程序中接收數(shù)據(jù),然后按照視圖的要求將這些數(shù)據(jù)格式化。謙卑對象同樣也可適用于數(shù)據(jù)庫網(wǎng)關、數(shù)據(jù)映射器ORM等場景中。
我們通常會認為服務是解耦合的,但是一旦服務之間使用了共享數(shù)據(jù),它們就會形成強耦合關系。按功能劃分服務的架構(gòu)方式,在跨系統(tǒng)功能變更時是比較脆弱的。那么對于這些橫跨系統(tǒng)之間的變更,我們應該如何處理呢?如果運用面向?qū)ο蠓椒?,可以采用模板方法模式或策略模式來將原先服務化設計中的大部分邏輯包含在基類中,然后針對特定的邏輯可以抽離到一個單獨的組件當中去。要是使用基于服務的方式,則可以用衍生類,為原有的服務添加新功能。
第六部分 實現(xiàn)細節(jié)。
這部分主要通過一個視頻銷售網(wǎng)站的案例分析,來闡述組建架構(gòu)以及依賴關系管理等,處理的思考過程。
我們需要注意的是,無論是數(shù)據(jù)庫、WEB UI還是應用程序框架,這些都是實現(xiàn)細節(jié),不應該成為架構(gòu)設計的阻礙。同時無論我們采用水平拆分的架構(gòu)(按層拆分)還是采用垂直拆分的架構(gòu)(按功能拆分),都需要將設計映射到對應的代碼結(jié)構(gòu)當中去。最好能夠使用編譯器來維護所選的系統(tǒng)架構(gòu)設計風格,這些細節(jié)都很關鍵。