移動端工程架構與後端工程架構的思想摩擦之旅(2)
此文已由作者黎星授權網易雲社群釋出
歡迎訪問網易雲社群,瞭解更多網易技術產品運營經驗
投放工程架構調整
有了前面的“理論基礎”,以及躍躍欲試的心動,我們來對投放工程的架構做一次調整和優化,原則是不改變原有的業務邏輯,目的是使投放工程的業務邊界和業務功能更為清晰。
舊工程架構
資源投放系統一共分為4個工程,分別是
-
後端前臺工程:kaola-resource-app
-
後端離線工程:kaola-resource-offline
-
後端後臺Web工程:kaola-resource-web
-
前端後臺fed工程:kaola-resource-fed
其中,kaola-resource-app和kaola-resource-offline提供純dubbo服務。app提供前臺服務,負責給其他業務線上獲取投放的素材資訊;offline提供離線服務,負責給其他業務的後臺系統獲取投放相關的資料。kaola-resource-web和kaola-resource-fed分別是投放系統的Web後端和前端工程,資源的分配、稽核、投放都在該系統完成。kaola-resource-fed屬於前端工程,不在本文討論範圍內,下面介紹三個後端工程的架構體系。
工程依賴關係
工程依賴關係如圖所示,主要分為幾類,分別是工具模組、介面模組、業務模組以及啟動模組,箭頭表示依賴關係。
-
工具模組
kaola-common-cache:主要包含Solo快取中介軟體的封裝,JVM快取相關的不在該模組裡。
kaola-common-util:工具類,包括常量、異常資訊及util類。
kaola-resource-search->kaola-resource-generic:ndir索引服務工程。
kaola-resource-schema(圖中未列出):存放投放自帶部分模板xml的地方,暫無其他工程引用。
-
介面模組
kaola-resource-api:提供線上和離線服務的dubbo介面。
kaola-resource-generic:通過mybatis與資料庫打交道,提供資料的工程,相當於DAO層。
kaola-resource-facade->kaola-resource-generic:提供Web層的facade介面,相當於Service層。
-
業務實現
kaola-resource-cache->kaola-resource-api、kaola-resource-generic、kaola-common-cache:提供業務報警、disconf配置、JVM快取、NCR快取、熔斷、業務監控、執行緒池管理等功能,且提供resource-api部分facade介面的實現、Service介面定義與實現,是resource-app工程的業務實現工程。
kaola-resource-provider->kaola-resource-facade、kaola-resource-api、kaola-service-util、kaola-resource-search、kaola-resource-generic:提供web工程facade介面的實現、Service介面定義與實現。
kaola-resource-service->kaola-resource-generic、kaola-resource-api:提供offline工程facade介面的實現、Service介面定義與實現。
kaola-service-util->kaola-resource-facade、kaola-common-util、kaola-resource-api:主要包含外部模板XML校驗業務的工程。
-
啟動模組
kaola-resource-app->kaola-resource-cache、kaola-common-cache、kaola-resource-api、kaola-resource-generic:app工程啟動入口,SpringBoot配置。
kaola-resource-offline->kaola-resource-service、kaola-resource-generic、kaola-resource-api:offline工程啟動入口,SpringBoot配置。
kaola-resource-fed:前端後臺工程
kaola-resource-web->kaola-resource-facade、kaola-resource-provider、kaola-resource-facade、kaola-resource-api、kaola-service-util、kaola-resource-search、kaola-resource-generic、kaola-common-util:web工程啟動入口,提供http服務。
現有工程問題
-
工程模組命名混亂
剛接觸投放工程的時候完全不知道從何入手,只能根據啟動工程的依賴關係找到對應的業務模組。總工程裡有4個小工程,通常找一個模組的業務實現不知道去哪個模組去找。例如,從命名上來看,並不知道kaola-resource-facade是web工程的業務介面,kaola-resource-provider是web工程的業務實現,kaola-resource-service是offline工程的業務實現,對新人來說命名不夠友好。
-
模組職責不清晰
由上面梳理的模組功能可以知道,kaola-resource-cache工程不僅承擔了快取管理、業務報警、熔斷等基礎業務,也是app工程的業務實現;kaola-resource-service既提供了業務介面,又提供了業務實現;kaola-common-util沒有發揮它作為工具類應該提供的職責和義務。總體而言,模組的職責可以通過一定的修改變得更為清晰。
-
工具類、常量類管理混亂
目前幾乎每個工程下面都有一個util包,且工程包含多個BusinessException/ParameterException類,帶來的問題是使用時不知道用哪個類。工具類與常量類應統一為一個工具類模組,統一管理。
-
版本依賴管理
每個工程的依賴目前都是獨立管理的,存在不同工程依賴中介軟體版本不一致的情況。主工程的pom管理機制可以優化一下,比如disconf是每個工程都要使用的,可以放在父工程使用dependencyManagement統一管理。
-
業務程式碼分支多
當前工程存在很多業務分支,遇到業務分支時大部分是通過if/else判斷的,修改一個業務點需要修改很多地方,通常很容易遺漏,造成隱藏的bug。
新工程架構
考慮到現有工程架構的特點,在新工程的設計上採用平滑過渡的方式,後端主體還是分為web/offline/app三個小工程,這三個小工程分別採用傳統的MVC架構。前端工程由於與後端工程關係不大,後續可以遷移到新工程裡。
工程依賴關係調整
針對舊工程中存在的不合理的點,以及工程中存在的問題,我們對工程及工程的依賴關係進行了如下調整。
紅色背景為刪除或整合的模組,包括kaola-service-util、kaola-common-util、kaola-common-cache。 黃色背景為重新命名的模組,目的是使模組功能定位更清晰,包括
-
kaola-resource-provider->kaola-resource-web-provider,表示web工程的業務實現
-
kaola-resource-facade->kaola-resource-web-facade,表示web工程的業務介面
-
kaola-resource-generic->kaola-resource-dao,表示物件關係對映,即DAO層
-
kaola-resource-service->kaola-resource-offline-provider,表示offline工程的業務實現
綠色背景為新增模組,包括kaola-resource-util、kaola-resource-offline-facade、kaola-resource-app-provider、kaola-resource-app-facade,模組的定義也比較明確。 紅色的線為可以移除的依賴關係,黃色的線表示修改為runtime依賴,綠色的線表示新增依賴。
經過上述調整後,一張更為清晰的投放工程架構圖便展現出來了。
工程架構基本思想
新的工程架構,模組間的職責與依賴關係更為清晰。
從模組的職責來說,淺藍色表示底層提供的工具類(包括各種util、快取、索引服務等);綠色表示資料物件關係對映服務層;黃色表示對第三方暴露的api;粉紅色表示對內提供的業務介面;土黃色表示業務介面的真正實現;深藍色則是工程的啟動入口,包含各種配置檔案。
從模組的依賴關係來說,啟動工程在編譯期僅依賴業務介面,執行時才會依賴業務實現以及與業務實現相關的底層服務,這一操作通過maven的scope標籤完成,編譯期編譯使用的標籤為<scope>compile</scope>
,執行時編譯使用的標籤為<scope>runtime</scope>
。索引、快取、工具類作為基礎服務以獨立的模組存在,需要與資料庫打交道的模組則直接依賴kaola-resource-dao即可。
對於當前的架構還不是最完美的,存在兩個問題。
-
kaola-resource-cache提供了kaola-resource-api的實現,應將這一部分的業務邏輯移至kaola-resource-app-provider中。
-
業務介面依賴了kaola-resource-dao,這一部分因為介面使用了dao層的Entity,需要重新規劃建模,去除對dao層的依賴。
該架構的設計可以做到業務層僅和介面打交道,在業務層實現業務邏輯時,不關心底層服務的實現。業務層也沒有辦法直接和dao層打交道,避免資料被業務層無故修改。
工程模組劃分
-
基礎模組/服務
kaola-resource-fed:前端工程單獨拆出,不與後端工程公用同一個git倉庫
kaola-resource-util:工具類、異常類、常量,可以被所有子工程引用
kaola-resource-cache:快取相關的模組,需要使用快取的工程引用此module
kaola-resource-index:索引工程服務
kaola-resource-dao:資料庫dao層
kaola-resource-api:暴露對第三方提供的所有服務api,包括online和offline介面
kaola-resource-facade-base:存放所有facade工程的基礎介面和異常類,上述流程圖沒有展示出來,但確實是有必要的基礎模組。
-
web工程
kaola-resource-web-facade:web工程服務暴露,僅提供facade介面和資料實體類
kaola-resource-web-provider:web工程服務實現,根據需要自定義service層元件
kaola-resource-web:web工程啟動類,compile依賴facade,runtime依賴provider
-
offline工程
kaola-resource-offline-facade:offline工程內部服務,僅提供介面和資料實體類
kaola-resource-offline-provider:offline工程服務實現,及部分kaola-resource-api實現,提供dubbo provider
kaola-resource-offline:offline工程啟動類,compile依賴facade,runtime依賴provider
-
app工程
kaola-resource-app-facade:app工程內部服務,僅提供介面和資料實體類
kaola-resource-app-provider:app工程服務實現,及部分kaola-resource-api實現,提供dubbo provider
kaola-resource-app-starter:app工程啟動類,compile依賴facade,runtime依賴provider
現有工程改造方案
工程模組改造
在上述改造原則基礎上,投放工程的模組改造計劃可以清晰地列出來。針對基礎模組來說,需要進行如下改造:
-
新增kaola-resource-facade-base工程,存放facade的異常類
-
kaola-common-cache重新命名為kaola-resource-cache
-
kaola-common-util重新命名為kaola-resource-util
-
kaola-resource-generic重新命名為kaola-resource-dao
-
新增kaola-resource-facade-base工程,存放facade的異常類
剩餘的三個工程,以resource-web工程為例,需要進行如下改造:
-
將kaola-resource-facade重新命名為kaola-resource-web-facade,存放對web工程提供的服務介面,將BusinessException和ParameterException移除放到facade-base工程中
-
kaola-resource-provider重新命名為kaola-resource-web-provider,將模組中的util遷移至resource-util工程
-
kaola-service-util中非業務相關的所有util全部移動到kaola-resource-util這個module中,剩餘業務相關的,移動到kaola-resource-web-provider工程
-
kaola-resource-web,將web對provider的依賴由compile改為runtime
offline和app工程採用類似的方案,不再贅述。
maven依賴改造
maven依賴改造的目的,一是減少由於版本依賴不一致帶來的新坑,方便第三方中介軟體的統一管理;二是對工程許可權有所約束,不至於程式碼亂放,難以維護。
-
共有的jar包依賴管理 在父pom增加dependencyManagement標籤,把常用的Spring、log、guava、junit、jsonserializer、disconf和網易自研的中介軟體等jar包統一進行版本管理。子工程需要相關元件時,僅需引入依賴,無需指定版本。
-
模組依賴許可權管理 由改造後的工程架構可知,啟動工程是沒有辦法接觸到業務實現的,這需要依靠runtime時再依賴業務實現模組來實現。因此,對於每個需要依賴*-provider的工程,都需要通過runtime來依賴。
-
api版本釋出管理 需要對外發布的包,依賴儘量使用provided引入。在父pom增加本地api釋出的版本,子工程如需依賴api或實現api的業務,需要引用父pom的api版本,api版本的升級,需要同時升級父pom和api模組工程兩個地方 resource-util工程與api工程管理一致。
TODO
-
kaola-resource-api遷移所有page相關的api介面
-
kaola-resource-fed遷移使用新的git工程
-
kaola-resource-cache邏輯遷移
-
kaola-resource-dao業務介面的依賴去除
架構調整總結
架構永遠是聊不完的話題,特別是涉獵了知識面較廣的後端以後,越發感覺需要學習的東西越來越多。本文分別從移動端和後端的架構思想談起,從中探索共同點,結合微服務的思想,探索過程中對多端架構有了思想的摩擦,總結了一套業務介面與業務實現的規範,能夠更好地為其他業務提供服務。在此基礎上,將這一套規範運用在投放工程上,完成從舊架構的問題分析,到新架構的優化設計與實現的整個過程。從結果來看,模組的職責更為清晰,程式碼的許可權與邊界得到了比較好的控制,對以後業務的縱橫向擴充套件、程式碼的健壯性都有了質的保障。
參考連結
-
https://zh.wikipedia.org/wiki/%E8%BD%AF%E4%BB%B6%E6%9E%B6%E6%9E%84
-
https://maven.apache.org/guides/introduction/introduction-to-dependency-mechanism.html
-
https://docs.gradle.org/current/userguide/dependency_types.html
免費領取驗證碼、內容安全、簡訊傳送、直播點播體驗包及雲伺服器等套餐
更多網易技術、產品、運營經驗分享請點選。
相關文章:
【推薦】 如何做好iOS應用安全?這有一把行之有效的“三板斧”