1. 程式人生 > >移動端工程架構與後端工程架構的思想摩擦之旅(1)

移動端工程架構與後端工程架構的思想摩擦之旅(1)

此文已由作者黎星授權網易雲社群釋出。

歡迎訪問網易雲社群,瞭解更多網易技術產品運營經驗

 

記資源投放後端工程的架構調整與優化 

 

架構思考

 

一直以來對軟體工程架構有著極大的興趣,無論是之前負責的移動端Android工程,亦或是現在轉到後端開發後維護的資源投放工程。可以說一個團隊中並非每個開發都能夠深入掌握架構知識,但需要每個人能夠擁有軟體架構的意識。架構是對工程整體結構與元件的抽象描述,是軟體工程的基礎骨架。架構在工程層面不分領域,且思想是通用的。引用維基百科對於軟體架構的定義^1

 

軟體體系結構是構建計算機軟體實踐的基礎。與建築師設定建築專案的設計原則和目標,作為繪圖員畫圖的基礎一樣,軟體架構師或者系統架構師陳述軟體架構以作為滿足不同客戶需求的實際系統設計方案的基礎。從和目的、主題、材料和結構的聯絡上來說,軟體架構可以和建築物的架構相比擬。一個軟體架構師需要有廣泛的軟體理論知識和相應的經驗來實施和管理軟體產品的高階設計。軟體架構師定義和設計軟體的模組化,模組之間的互動,使用者介面風格,對外介面方法,創新的設計特性,以及高層事物的物件操作、邏輯和流程。

 

架構的合理設計可以解決面對複雜系統時可能面臨的很多問題,例如:

  • 業務邊界與模組職責劃分問題

  • 程式碼許可權控制問題(資料庫不應直接被業務方呼叫)

  • 程式碼重複,邏輯分支多,壞味道多的問題

  • 由於考慮不周,可能存在隱藏bug

  • 修改一個邏輯需要修改N個地方程式碼邏輯

從實際的實踐來看,的確如此。以前在移動端做的架構設計流程,在後端重新得到了實踐。

 

移動端架構思考

 

尚未接觸到強大的Spring容器之前,我一直探索著在移動端有一種能夠在編譯期暴露服務宣告,執行時自動注入實現類的做法;接觸到Spring以後,得以理解這其實就是IoC容器的概念。Android的元件化思想,以及網上釋出的各類元件化的技術文章,給了我很多值得借鑑的思路。客戶端的程式碼一般是以module來組織的。一個module,既可以配置成為一個獨立釋出的庫,也可以編譯成一個單獨的apk。元件化的概念正是利用了module這一特點,將一個大工程中的業務拆分成一個個module,各個module間的業務相對獨立,元件間通過各自暴露的業務介面實現通訊。基於此思想的移動端架構模型可以使用下圖來表示。

 

點選檢視原圖

該架構模型由5個部分組成,分別是Toolkit/ToolkitSDK module、基礎元件庫/基礎元件庫module、基礎服務介面/業務服務介面module、服務排程中心module以及業務module。

  • Toolkit/Toolkit SDK

Toolkit是工具類及與工具類相關的SDK的集合。工具類屬於工程架構裡最基礎的模組,提供了通用的方法與工具類服務(工具類服務是指可以被抽象成一個獨立的與業務無關的基礎服務,如快取、資料庫操作等)。工具類通常作為最底層的module,被其他所有模組引用。

  • 基礎元件庫/基礎元件SDK

基礎元件庫是基礎元件及相關SDK的集合。基礎元件庫提供與業務相關的基礎元件,是構建一個移動端應用所需要的通用元件的集合。它與工具類的區別在於基礎元件庫可能會包含少量業務邏輯程式碼,是無法拆分給其他應用使用的;另一方面,基礎元件庫是基礎服務介面的實現,是不對業務層暴露的,避免了業務層與基礎SDK打交道,有利於整體替換底層基礎框架的實現(例如Volley替換為OkHttp、Fresco替換為Glide)。

  • 基礎服務介面/業務服務介面

基礎服務介面聲明瞭一組通用的基礎服務,業務層通過基礎服務介面獲取基礎服務,如網路請求、圖片載入等。業務服務介面聲明瞭一組該模組提供給其他模組的服務,業務之間的通訊也是通過服務介面來完成的。例如首頁模組需要獲取購物車的商品數量,首先通過服務排程中心獲取購物車的服務介面,再通過服務介面呼叫購物車獲取商品數量的介面方法即可。

  • 服務排程中心

服務排程中心,是一個介面收集與管理的容器。服務排程中心將所有基礎服務介面與業務介面收集起來,通過一定的方式與它們的實現類進行繫結。所有的業務都需要通過服務排程中心才能夠獲取到服務。服務的註冊與發現和Spring容器的IoC思想是類似的。

  • 業務層

業務層是每個業務的具體實現的集合。業務層的業務之間是沒有直接引用關係的,業務層提供了業務服務介面中暴露的服務的具體實現。業務之間的通訊需要通過服務排程中心獲取其他業務的服務介面。

 

移動端架構小結

通過介面服務架構模型,模組之間是高度解耦的。業務負責人唯一需要維護的公共部分便是這個模組在業務服務介面中暴露的服務。對於業務服務的介面功能增改變得非常方便,業務實現的邏輯更改、程式碼優化等,只要不改變服務介面的簽名,就不需要其他業務方改動任何程式碼即可完成,由此團隊的開發效率是非常高的。

 

後端架構思考

 

對於後端工程來說,架構的設計與實現必定是與工程的業務難度及複雜程度相關的,如果只是很簡單的業務模型,就沒有必要弄得太過複雜,避免得不償失。本人只接觸了幾個月後端知識,對於後端的架構體系與演進過程處於不斷地學習和探索中。投放系統是我接觸到的第一個完整的後端工程,其中Web工程採用傳統的MVC架構^2,對我具有很大地學習和借鑑意義,專案架構如下圖所示。

 

點選檢視原圖

該架構縱向劃分成展示層、控制層、服務層、物件關係對映層和資料服務層5個部分,層級間通過AOP的方式插入了業務監控、日誌、許可權控制、統計分析等功能。

  • 展示層(View)

展示層是系統與使用者打交道的地方,提供與使用者互動的介面。對於使用者而言,只有展示層是可見的、可操作的。展示層對於某些工程來說不是必須的,例如提供純後臺服務的工程。

  • 控制層(Controller)

主要負責與Model和View打交道,但同時又保持其相對獨立。Controller決定使用哪些Model,對Model執行什麼操作,為檢視準備哪些資料,是MVC中溝通的橋樑。在Controller層提供了http服務供展示層呼叫。在依賴管理中,控制層需要依賴服務層提供服務。

  • 服務層(Service/Facade)

服務層是業務邏輯實現的地方,上層需要使用的功能都在服務層來實現具體的業務邏輯。服務層就是將底層的資料通過一定的條件和方式進行資料組裝並提供給上層呼叫。服務層可以拆分為業務介面和業務實現,業務實現可以對外部隱藏。在投放工程中,控制層既依賴了業務介面,又依賴了業務實現。後面的改造我們可以看到,編譯期紅色線依賴是完全沒有必要的。服務層需要依賴資料關係對映層與持久層的資料打交道。

  • 物件關係對映層(ORM)

物件關係對映層的作用是在持久層和業務實體物件之間作一層資料實體的對映,這樣在具體操作業務物件時,只需簡單的操作物件的屬性和方法,不需要去和複雜的SQL語句打交道。ORM使得業務不需要關心底層資料庫的任何細節,包括使用的資料庫型別、資料庫連線與釋放細節等。物件關係對映層只依賴資料服務層提供服務。

  • 資料服務層(Data Server)

資料服務就是提供資料來源的地方。資料服務可以提供持久化資料及快取資料。持久,即把資料(如記憶體中的物件)儲存到可永久儲存的儲存裝置中(如磁碟)。持久化的主要應用是將記憶體中的資料儲存在關係型的資料庫中,當然也可以儲存在磁碟檔案中、XML資料檔案中等等。而快取是將資訊(資料或頁面)放在記憶體中以避免頻繁的資料庫儲存或執行整個頁面的生命週期,直到快取的資訊過期或依賴變更才再次從資料庫中讀取資料或重新執行頁面的生命週期。資料服務層是資料來源頭,處於架構的最底層。

 

後端架構小結

後端工程,更加註重層級的概念,每一層的職責非常明確。展示層負責與使用者進行頁面互動,控制層合併業務資料並控制View的展示,服務層則是實現業務邏輯的聚集地,物件關係對映層在業務層和資料服務層之間建立通道,而資料服務層則提供資料。總體而言,投放工程的MVC架構給我的感覺是比移動端架構複雜,層級多,職責分工明確,帶來的問題是層級間的互動也比較麻煩。另外服務層裡承載了幾乎所有的業務邏輯,層級偏重,如果沒有好好地梳理業務邏輯劃清邊界,很容易把服務層搞成一鍋粥。清晰的模組職責劃分,可以幫助服務層更好地為控制層服務。

 

架構思想的摩擦

 

可以看到,客戶端與後端有著非常相似的架構模型。

  • 從程式碼組織的角度:以module作為層級程式碼組織的基本工具,分為工具庫、基礎元件庫(中介軟體)、服務介面/API、服務層/業務層、檢視層等。module間的依賴關係幾乎是一樣的。

  • 從業務模型的角度:後端工程分為交易組、商品組、售後組、客服組等,對應移動端的交易鏈路浮層、商品詳情頁、售後詳情頁、幫助與客服頁等,每個業務是由不同的組負責的,業務之間通過約定的介面相互提供服務,各種各樣的業務模型聚合成了整個系統。

  • 從功能服務的角度:分為業務服務介面的暴露、業務服務實現的隔離、業務服務的查詢與註冊。

下面從功能服務的角度,詳細說明本文在思想摩擦過程中想要表達的觀點。

 

業務介面的作用

 

業務介面,可以認為是這組業務向外暴露其功能的一套標準。標準一旦形成併發布,就需要業務方持續維護這套標準,使得標準變得完善和穩定。同時標準可以更新升級,可以通過版本來實現,提供新的功能。業務介面一般具備以下特性:

  • 業務介面包含一組Java的介面集合以及與這些介面相關的POJO,通常打包成一個JAR/AAR包。

  • 業務介面只提供介面功能的定義,不包含任務業務邏輯。

  • 業務介面可以進行版本管理,一旦版本釋出,則該版本的介面不再可變。業務需要新增功能時,只需要在原有業務介面的基礎上,增加新的功能介面或方法,同時升級業務介面版本號併發布。

其他業務方需要使用該業務的功能,只需要引入該業務的JAR/AAR包,通過服務排程中心獲取該服務介面即可。

 

業務邏輯的存放

 

業務介面僅提供了功能的定義,不包含任何業務邏輯。那麼,業務邏輯(即介面的實現類)放哪裡呢?不管是移動端架構還是後端架構,在工程領域,業務邏輯在任何時候都不應該對業務的使用方暴露。這樣做有兩個好處:

  • 業務方只關心功能,不關心功能實現的過程。隱藏業務的實現邏輯可以降低業務方使用該功能的成本及複雜度。

  • 業務功能的後端邏輯改動及必要的技術優化、效能優化,只要不更改介面簽名,則不會影響當前的業務方使用。

一般情況下,業務的邏輯實現會放在單獨的業務模組中,該業務模組僅限工程內部引用。後端傳統的MVC工程架構把業務的實現邏輯放在了Service/Facade層,層級之間的類不相互引用;而基於驅動領域的設計模型把業務的實現邏輯限定在了一個領域/子域裡,領域之間通過界限上下文繫結。在移動端,時下較為熱門的眾多元件化方案,也是將一個獨立的功能模組作為單獨的module,module可以獨立編譯為apk,也可以通過aar的方式整合到主Application中。

 

業務邏輯的隔離

 

業務的使用方包括工程內部的上層業務和外部服務,業務介面與業務邏輯有必要進行程式碼級別的隔離,這樣才能避免上層業務引用到業務邏輯的程式碼。通常,工程的每個模組負責不同的功能,模組之間的引用關係通過依賴管理工具(如Maven或Gradle)來配置。我們可以巧用依賴管理工具的runtime compile機制來實現執行時依賴。即在編寫對外介面的時候,不直接引用包含業務邏輯的module,等到編譯的時候再把業務邏輯程式碼一起編譯進來,然後在執行時通過一定的方式呼叫對應的業務邏輯。

  • Maven通過在dependencyManagement的依賴中加入runtime標籤實現^3

  • Gradle通過在dependencies將compile改為runtime實現^4

下面的兩張圖簡單介紹了後端工程和移動端工程基於業務邏輯隔離的工程架構思路。其中,虛線表示runtime compile依賴,實線表示正常的依賴關係。

 

點選檢視原圖

工程的啟動入口幾乎不包含業務程式碼,只包含配置檔案。Controller層是一組RestfulApi的集合,給前端和客戶端提供http請求服務,業務介面/API是一組dubbo介面,給其他工程業務方提供RPC呼叫。Controller層在編碼的時候只依賴Service/Facade介面,在編譯期依賴Service和Facade介面的實現。這樣設計還有一個好處是對DAO層的保護,DAO層只和Service層打交道,Controller以及對外提供的dubbo介面是引用不到的,更好地保護資料安全。

 

點選檢視原圖

在移動端的架構中,單Application+多module已經成為主流。每個module負責一塊獨立的業務,如首頁、訂單、購物車等,核心模組也可以拆分為獨立模組,如網路引擎、圖片引擎。這些獨立的模組可以抽離出BusinessService/CoreService服務介面,模組間的互動只需要通過Service介面通訊即可,業務對於其他的p_CoreSDK/Business的邏輯實現是不可見的。

 

業務介面的註冊

 

有了業務介面和業務實現,還需要一種在執行時把它們“粘合”起來的工具,這一過程可以稱為業務介面的註冊。當業務方訪問業務介面時,這個工具需要幫助我們查詢到對應的業務實現。控制反轉(IoC)或依賴注入(DI)的思想給我們提供瞭解決辦法。

在後端工程中,Spring是最為常用的IoC容器之一。Spring在執行時根據配置檔案或註解動態生成物件,再由變數註解通過Java反射注入到對應的例項中。因此程式碼中只需要通過在全域性變數宣告相應的註解即可完成業務介面的註冊。

移動端由於有限的硬體資源,更多地把CPU時間分配給了頁面渲染,保證應用體驗流暢,不太可能在應用啟動的過程中大量通過反射生成例項物件,因此移動端並沒有出現Spring框架。儘管如此,依賴注入的思想是通用的。通常移動端只需要保證在執行時能夠獲取到對應的業務實現,幾乎沒有在執行時動態改變業務實現的需求,聰明的工程師想到了把服務的註冊提前到編譯期進行,這一過程可以使用JDK提供的Annocation Processing Tool完成(例如Dagger2),也可以在編譯生成Class位元組碼以後使用ASM操作位元組碼註冊實現(如ARouter)。

 

 

免費領取驗證碼、內容安全、簡訊傳送、直播點播體驗包及雲伺服器等套餐

更多網易技術、產品、運營經驗分享請點選

 

相關文章:
【推薦】 常見的三種撞庫方法
【推薦】 全域性腳手架了解一下【fle-cli】