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

緒論

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

分層架構設計

軟件,應該根據其職能分成多個層次。分層架構設計思想,有很多成功的例子。如網絡設計上,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:後面打算再找時間談一下海量規模的軟件架構的設計原則和模式。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章