1. 程式人生 > >軟體架構設計原則和模式(上):分層架構設計

軟體架構設計原則和模式(上):分層架構設計

緒論

本文打算探討一下軟體架構設計的一些設計原則與經過實踐驗證的設計模式。這些軟體架構設計的原則和模式已經有幾十年的歷史了。

分層架構設計

軟體,應該根據其職能分成多個層次。分層架構設計思想,有很多成功的例子。如網路設計上,OSI七層網路模型,就把網路應用軟體,按照功能分成了職能各異的七個層次。實際網路中使用的TCP/IP協議,也遵循OSI七層網路模型,只是把OSI的應用層,表示層和會話層全部糅合在應用層內而已。

可以說,按照功能進行分層,是一個經過實踐檢驗、行之有效的軟體設計方案。

前端和後臺

從大的範圍來分,軟體可以分為兩個層次:前端和後臺。這兩個概念大家應該都很熟悉。很多程式設計師招聘廣告,都區分前端工程師和後臺工程師。

前端

前端,也常稱為UI。是使用者介面應用程式。使用者介面應用程式,是直接和使用者進行互動的軟體。常見的前端應用有:命令列程式,Web應用,桌面應用(包括移動裝置應用)。除了命令列程式外,都是圖形化介面。本文只介紹圖形化介面的前端程式。

前端程式,負責與使用者進行互動。負責接收和校驗使用者輸入,並向用戶反饋輸出。其業務操作是委託給後臺來實現的。

前端程式,必用的設計模式,是20世紀80年代發現的MVC模式。所有成功的前端應用,都使用了MVC模式或者它的一些變體。

MVC模式,MVC全名是Model View Controller,是模型(model)-檢視(view)-控制器(controller)的縮寫。它是Gof設計模式一書中介紹的第一種設計模式,是設計模式之母。

MVC模式,就是用控制器來管理使用者輸入、輸出和圖形介面。資料來自模型部分。模型Model實際上集中管理了業務資料。這使對同一種業務資料展現多種圖形介面成為了可能。MVC模式,分離了顯示邏輯和業務邏輯。

應用MVC模式的前端應用中,模型Model是通向後臺系統的通道。

後臺

前端應用負責提供與使用者互動的軟體。後臺則向前端提供業務服務。所有業務相關的操作和服務應該由後臺來實現。

前端和後臺,可以是在同一個程序中的,也可以是分屬不同程序的。

一般,較簡單或者小型的單機系統,前端和後臺都在同一個程序中。也就是都屬於圖形應用程式(或者命令列應用程式)。這種應用程式,前端部分程式碼,通過API呼叫直接呼叫後臺提供的業務服務。如Office軟體就是單機系統。

複雜或者分散式系統,前端和後臺屬於不同的程序,前端通過程序間呼叫機制來呼叫後臺提供的業務服務介面。目前常用的程序間呼叫機制有:WebService、REST、基於TCP自己實現的通訊協議,程式語言自己定義的通訊協議,作業系統自己定義的通訊協議等。如,現在很多企業級應用軟體,Web應用,網際網路應用等。

後臺系統本身,也需要分為多個層次,包括:介面層,業務層,助手層。分別對應於大家應該都很熟悉的JavaEE中的表現層,業務層,持久化層。

介面層

介面層,在JavaEE中稱為表現層。就是後臺系統對外的介面層,用於實現跨程序呼叫。介面層的程式碼,和你使用的程序間呼叫機制有關。如,你使用WebService,那麼介面層就是用來處理WebService請求的程式碼;你使用Rest,那麼介面層就是處理Http請求和返回Http響應的相關程式碼;你使用的是RMI這樣的語言定義的通訊協議,介面層就是用RMI協議接收和傳送資料的相關程式碼。

介面層,應用了Gof設計模式中的Façade門面模式。它向前端(客戶端)提供了一個簡潔一致的介面,隱藏了系統的複雜性。只要保證介面不變,那麼後臺的業務層和助手層程式碼再怎樣變化,對前端(客戶端)程式都是透明的。

JavaEE中稱之為表現層,意為和Web圖形介面有關。這是因為當時JavaEE提出這種分層時,Struts等JavaWeb前端框架正大行其道。Struts等會把html頁面返回給瀏覽器,具備呈現圖形介面的功能。

但目前,前端和後臺完全分離的應用很多,並已經成為一種趨勢。如,前端是桌面應用或者移動應用,顯然只需要和後臺交換業務資料,不需要後臺返回圖形介面。Web開發中,目前也流行Html頁面上嵌入JavaScript程式碼通過AJAX向後臺交換業務資料,而不是要求後臺返回html頁面。介面層不再需要返回html頁面,只需要返回資料。

因此這裡我命名為介面層而不是表現層,更為貼切。

另外,對於前端和後臺在一個程序中的軟體,無需定義介面層。前端部分直接通過API呼叫後臺部分的業務程式碼即可。

業務層

業務層,負責定義領域物件,完成業務邏輯的處理。它向前臺提供後臺需要的所有服務。

每一個應用程式,都有其需要解決的問題。針對其問題域,需要劃定問題範圍,進行數學建模,識別領域物件,並定義各個領域物件之間的關係。

數學建模和識別領域物件的方法有多種。下面分享一下我一直使用的一種方法:

1,請需求方描述清楚問題是什麼,想要得到什麼結果。

2,描述自己的解決方案,能夠做到什麼,尋求需求方的確認。

3,對解決方案文字化。找出其中所有名詞和動詞。名詞就是領域物件的候選物件。動詞是領域物件的方法的候選物件。尋找名詞之間的制約關係。

4,確定領域物件的關係。我使用關係資料庫的設計方法,確定物件之間是一對一關係,多對一關係還是多對多關係。

關係資料庫實際上和麵向物件系統是完全等價的。這可以從很多O-R mapping框架上看出來。

我對關係資料庫設計非常熟悉,因此我總是使用這種方法識別和定義領域物件。即使在一些應用場景中,領域物件根本不需要持久化,我還是用這種方式來考察領域物件。

5,根據識別出的領域物件,及其相互之間的關係,需要實現的方法,用面向物件的思維編碼。用面向物件的思維編碼,不意味著必須使用類。用C這樣的程序式程式設計語言也可以用面向物件的思維編碼。只是你心中要放著物件這個概念即可。如,我用Python編碼時,很少使用類,經常是直接使用函式。但心中還是存著“物件”的理念的,這樣寫出的程式碼才不會亂。

助手層

業務層程式碼,會需要使用一些第三方軟體提供的服務或者其他更低層級的自己開發的軟體服務,才能實現其業務邏輯。這些不屬於介面層,也不屬於業務層的程式碼,我們稱其屬於助手層。助手層程式碼是為了協助業務層程式碼實現功能而存在的。

助手層,在JavaEE中稱為持久化層。因為JavaEE是一個企業級軟體架構設計方案。其針對的是企業的資訊系統。其業務邏輯一般就是操作資料庫。

資料庫的讀寫訪問,是與具體業務邏輯無關的,是幫助實現業務邏輯的。因此JavaEE稱為持久化層。但這個定義也不全面。因為還是存在很多系統,其除了訪問資料庫外,還需要其他服務才能實現業務邏輯。如,一個視訊網站,它可能需要對上傳的視訊檔案進行格式轉換,進行檔案切分等;OpenStack,除了訪問資料庫,還需要訪問各個Hypervisor的管理軟體來管理虛擬機器,需要訪問網路部分程式碼,管理虛擬網路,需要訪問儲存部分程式碼,訪問塊裝置和檔案等。

因此,我認為稱之為助手層比持久化層更具普適性。

假設我們的應用是一個類似美團這樣的優惠券應用,需要操作地圖的功能。對優惠券應用來說,自己的領域物件包括商戶、優惠券、使用者等。操作地圖的功能,不屬於領域物件,也就不屬於業務層的範圍。它是為服務層服務的。因此操作地圖的功能,在優惠券應用中就屬於助手層。助手層使用的地圖API,實際上可能是呼叫百度地圖服務。

對於百度地圖服務來說,它相當於一個後端系統,其也由介面層、服務層和助手層構成。地圖的位置資訊、興趣點等是它的服務。

因此,服務層和助手層的區別,實際上是邏輯概念上的區別。一個系統的服務層,對於其他系統可能就是助手層。

比如,一個企業資訊化應用,需要處理一些時間、字串、集合等相關的函式。這些函式在這個應用中就屬於助手層。因為時間,字串,集合都屬於我的系統的領域物件,它們是為業務服務的。是更低一個層級的。

總之,後臺部分中,不屬於介面層和業務層的所有程式碼,都屬於助手層。

業務層和助手層的區別

我們以openstack為例具體說明業務層和助手層的區別。

openstack的業務層,包括其定義的server,也就是虛擬機器。

而虛擬機器的業務邏輯程式碼,需要呼叫hypervisor 管理工具。如果使用KVM這個hypervisor,就需要使用libvirt的客戶端庫。libvirt客戶端在openstack中就是助手層程式碼。

而libvirt客戶端庫又會通過網路呼叫libvirt後臺。在libvirt後臺系統中,也包括了介面層,業務層,助手層這樣的層次。

libvirt內部定義了虛擬機器這樣的領域物件,對其的操作,需要使用qemu命令列程式。qemu命令列程式在libvirt中就屬於助手層。

這就像是剝洋蔥,剝開一層裡面還有一層。你在剝哪層,哪層就是業務層,其內部的層次就屬於助手層。

讓我們上升到哲學的高度。這種分層的研究方法,就是形而上學的方法,是用孤立、靜止、片面的觀點觀察和研究世界的思維方式。一次聚焦和處理軟體系統的一個層面的邏輯。不採用這種方法,眉毛鬍子一把抓是做不好軟體的。

小結

分層的軟體設計思想已經存在很多個年頭了,在電腦科學的各個領域都證明了它的成功。前端(MVC模式)和後端(介面層-業務層-助手層)的分層設計也經過了幾十年大量軟體的證明。

分層的思想,就是每一個層次專注做一件事情。每一個層次都為上層提供服務。每一個層次對於其上層來說,都是可以複用的。

如,助手層的程式碼,時間、字串等函式,換一個應用也可以用上。後端部分,可以為多個前端應用提供服務。前端一開始可能是桌面應用,後面變成Web應用,之後可能再開發移動應用,後端都不需要改變。一個框架的服務層程式碼,在另一個應用中,可以成為助手層程式碼。一個應用的整個後臺,也可能成為另一個應用的助手層。

分層設計的軟體,結構清晰,程式碼各司其職,能夠最大限度地重用程式碼。

PS:後面打算再找時間談一下海量規模的軟體架構的設計原則和模式。