大風車Android客戶端的架構演進
前言
- 以下內容不牽涉具體代碼實現,也不包含插件化相關知識。
- 沒有銀彈,只有根據當前的與可預見的業務情景不斷調整的架構方案。
- 閱讀正文將花費您大約30分鐘。
- 本文會隨時間持續改動。
大風車從第一版發布開始到現在已經走過了兩個多年頭,陸續上線發布了二十多個版本,從一開始的提供web容器包裝h5的簡陋版本,發展到現在由九個專職原生開發同學及數位前端同學支持的12w行(統計數據來自 SonarQube )代碼的規模。架構的可用性半衰期隨著業務體量的增長而縮短,那么如何支撐現有業務的維護及后續的業務開發是對我們的一大挑戰,而本人作為經歷了從零開始的開發人員,下面帶大家回顧一下這兩年來的大風車Android客戶端的架構變化。
組件化與模塊化
首先來明確兩個概念: 模塊(module) 和 組件(component) 。
什么是組件?
組件是語言層面的劃分,側重于 功能重用 。在Android里表現為一個UI控件,一個工具集合,一個路由系統。
什么是模塊?
模塊則是業務層面的劃分,側重于 業務解耦 。在Android表現為一個業務module。同時模塊中也可以包含任意個組件。
兩者可以說是在分治方向和粒度上的區別。
大風車Android客戶端在模塊上有三個維度上進行項目拆分:一是 通用功能庫 ,這個維度上包含了基礎樣式庫、通用工具庫(比如上傳/下載、圖片處理、壓縮等等),即可重用的通用功能;二是 業務類型庫 ,與具體業務相關,包含了可重用的業務功能;三是大風車客戶端作為 主工程 ,他們都表現成一個單獨的git項目,有自己的版本號與分支,前兩個維度穩定后發布在Maven倉庫上( Nexus 或 Artifactory 兩種開源實現都可,具體取決于公司的技術棧),另外三者都有自己的項目地址和版本號,每個大風車發布上線的版本都會依賴這些庫的對應版本。同時,三者最淺層的區別就是主工程的對外版本號不以開發人員的意志為轉移,需要跟著產品的需求和改動走。
當然,上述的分層不是一蹴而就從一開始就設計好。因為初始的項目規模比較小,追求快速迭代和盡早上線,剛開始的大風車只有一個主項目,其他庫都是之后因為重構或者因為新的需求進行拆分或者新建而產生的。
分層
隨著項目逐漸臃腫,代碼難以維護,需要我們進行解耦,而實現解耦常見有兩種手段,一種是 模塊化 ,另一種則是 分層 。通過上面的描述來看,我們已經實現了模塊化,下面我們就來看看如何實現分層。
大風車主項目是基礎的 MVC 結構,采用這樣的設計大部分原因是歷史遺留問題,隨著業務復雜度的提升,我們進行了上述的分模塊開發,而MVC的局限性在于會讓業務代碼塞滿 Activity 的各個角落。拿我們的車輛詳情頁舉例,由于各種車輛操作加上賬號資源角色的判斷,現在的車輛詳情頁Activity代碼行數已有1930行,夸張的技術債務帶來的代價是舊代碼難以維護,新需求難以迭代。
業務驅動技術,技術服務業務。故以現在流行的 MVP 框架為導向,結合 CleanArchitecture 的思想,通過 RxJava 解耦視圖與數據的通信,同時也很好的支持了單元測試。
從協議到路由
在上面我們進行了模塊化和分層,而另一大常見的問題就是Android中的 視圖跳轉 。因為業務頁面越來越多,有些共用的頁面可能只是參數傳值或者啟動方式的上的區別,需要不同的開發去重復寫 Intent ,這些差異極小的 Intent 會遍布在項目里各個角落。有時候改了一個地方會因為遺漏等原因而牽一發而動全身。我們的處理方式是約束了統一的跳轉協議格式,所有的業務視圖都通過給定的協議去跳轉,而跳轉協議由統一的協議處理工具類去解析。
但隨著不斷編寫同樣的協議我們發現這樣的開發體驗不太好,畢竟協議是字符串,不斷硬編碼字符串需要不斷查詢協議文檔,所以之后我們的計劃是用注解實現的路由系統來輔助當前協議的解析方式,通過編譯時生成代碼的方式來改善開發體驗。
小結
所有的架構方案因為設計者的局限性或者項目規模大小的限制,所以可能可以很好的滿足當前或者半年后的開發設計和體量,對一年后的需求就難以支撐,所以需要不斷的根據業務發展來完善我們的設計。請用發展的眼光看待此類問題,同時我們也將持續改進。
來自:https://blog.souche.com/dfc-android-architecture-evolution/