BeeHive,一次 iOS 模塊化解耦實踐
去年GMTC大會天貓無線專家分享了天貓iOS是如何做解耦的,并提到了其中的模塊化方案BeeHive,后來他將其整理成文章,推薦閱讀:
-
手機天貓解耦之路
在本文,天貓的戴鵬繼續分享了BeeHive的目的,舉例說明最佳實踐,并且剖析其結構和原理。
1.為什么需要BeeHive?
在天貓App的快速發展過程中,人員不斷壯大,業務不斷復雜,代碼量隨之增多,帶來的是協作開發中遇到各種各樣的問題。
你是否曾在這樣的環境下艱難開發?畏手畏腳地邊做需求邊改BUG。
同時iOS的工程代碼的耦合可能是這樣的:
AppDelegate中包含大量庫的init以及其他操作,少則幾百行,多則上千行,無關代碼堆積在其中,維護成本極高,不同庫的調用邏輯互相交錯,如下圖所示:
面條式的耦合,導致上層業務受限于底層基礎庫的依賴影響,BUG排查緩慢、新功能增加效率隨代碼量遞增而不斷遞減。
1.1 開發中主要問題
開發過程中總結了以下App開發中遇到的問題:
-
功能代碼之間的依賴復雜,可維護性差
-
協同開發過程中,并行開發存在block情況
-
功能界限不清晰,基礎功能模塊變動,會導致上層業務受到影響
-
各團隊負責功能模塊,在主工程中有耦合代碼
-
上層業務會出現反向提供功能給底層情況
-
性能分析優化,隨代碼增加變得困難
1.2 App和開發人員的訴求
一個App應該有如下特性:
-
功能可維護性
-
功能可用性
-
功能具有良好性能
-
功能可分析,可量化
-
功能可單元測試
開發人員希望協同開發中能夠做到以下幾點:
-
不希望被別人block住開發
-
依賴庫版本、約定的接口要穩定
-
以最少侵入式代碼來接入某個功能
代碼隔離開發問題,通過Cocoapods得到解決,代碼層面達到了分割,但邏輯功能上的耦合問題還是無法解決。開發人員希望在擴展業務的同時做到快速穩定,因此需要有一種App模塊解耦方式來讓開發人員中免受依賴關系的痛苦,于是讓開發人員產生了打造一個全局基礎框架的想法。
2. BeeHive的最佳實踐
BeeHive的使用方法可以參考BeeHive的README:
https://github.com/alibaba/BeeHive
這里舉一個實際開發中的例子。
2.1 3D-Touch例子
2.1.1 場景1:搭建3DTouch場景
iPhone 6s及以上的設備支持3D-Touch后,幾乎所有應用都在適配其特性,按照慣例,在AppDelegate中包含如下代碼:
-(void)application:(UIApplication *)application performActionForShortcutItem:(UIApplicationShortcutItem *)shortcutItem completionHandler:(void (^)(BOOL))completionHandler
{
....
}
這意味著AppDelegate要增長代碼行數,實則QuickAction的功能沒有必要寫在AppDelegate中。利用BeeHive框架特性,創建3DTouch Pod,獨立3DTouch相關業務功能。
-(void)modQuickAction:(BHContext *)context
{
....
//process context.shortcutItem
}
2.1.2 場景2:3DTouch需要動態化,可量化
一個動態配置quickAction需求的到來,以往的做法需要引入配置Module,創建對應一系列調用流程,這時只需要調用配置Service即可,而且希望更早的更新quickActionItem,于是可以調用modInit來實現。
-(void)modQuickAction:(BHContext *)context
{
....
//update config by configCenter Service
}
產品方還希望知道用戶都用了哪些QuickAction,這時調用UserTrack Service即可,諸如此類的一個上層業務,開發人員要調用Log,Cache等等服務,采用BeeHive Service形式后只需一行調用即可。
2.1.3 場景3:3DTouch需要做到個性化
在沒有服務端的情況下,如何做到QuickAction個性化,注冊并提供了3DTouchBHService,給其他業務調用比如某個功能頁面
-(void)updateAccessTimesWithActionURL:(NSURL *)actionURL
{
....
// save view controller access times by cache service
// update local quickAction Items by access times and any other element
}
上面三個典型場景主要涉及的到BeeHive幾大功能點:
-
Module的創建,感知App生命周期
-
對內引入、調用Service
-
對外提供Service
-
功能移植,無需copy,podfile中增加pod源
整個3DTouch開發過程中不涉及其他其他功能的具體實現,面向切片編程過程中,只要關心自己模塊對應的需求即可。
3. BeeHive結構與原理解析
BeeHive借鑒了Spring Service、Apache DSO的架構理念,采用AOP+擴展App生命周期API形式,將業務功能、基礎功能模塊以模塊方式以解決大型應用中的復雜問題,并讓模塊之間以Service形式調用,將復雜問題切分,以AOP方式模塊化服務,舉例來說日志、埋點模塊采用AOP方式后,業務方不需要考慮日志、埋點的相關代碼,只要以createService去聲明調用Service即可。
相應的BeeHive架構如下:
Core + plugin的形式可以讓一個應用主流程部分得到集中管理,不同模塊以plugin形式存在,便于橫向的擴展和移植。
圖中的BHContext,是BeeHive的配置文件,提供全局統一上下文信息。圖中的BHCore即BeeHive提供注冊、創建Module、Service邏輯,Module、Service注冊和調用邏輯只和核心模塊相關,Module之間沒有直接的關聯關系。
BeeHive核心思想涉及兩個部分:
-
各個模塊間調用從直接調用對應模塊,變成調用Service的形式,避免了直接依賴。
-
App生命周期的分發,將耦合在AppDelegate中邏輯拆分,每個模塊以微應用的形式獨立存在。
BeeHive提供了三種不同的調用形式,靜態plist,動態注冊,annotation。Module、Service之間沒有關聯,每個業務模塊可以單獨實現Module或者Service的功能。
3.1 Module
圖中包含了主要的BeeHive啟動過程以及Module的時序邏輯。Module的事件分發源于BHAppDelegate中的triggerEvent,對應GlobalContext也在回調中提供給業務方。
BHAppDelegate中除了回調系統的事件,還將App生命周期進行擴展,增加ModuleSetup,ModuleInit,ModuleSplash,此外開發人員還可以自行擴展。
擴展周期過程中,同時加入Module分析量化功能,每個模塊Init的耗時均可計算出來,為性能優化做到數據上的支持。一個App的業務增多過程中,通過分析定位Module的Init耗時可以確定需要優化的Module。
Module遵循BHModuleProtocol后,能夠捕獲App狀態的回調,并擁有App生命周期內的全局上下文,通過context可獲取配置參數,模塊資源以及服務資源。
以BeeHive作為底層框架的App,除了解耦帶來的便利,開發人員在開發新App過程中涉及相同功能的Module,無需重復造輪子,直接移植Module,開發一個App如同拼裝積木,能組合需要的功能業務。
3.2 Service
上述圖中包含Service相關的邏輯,業務A可以通過createService直接調用服務,Module根據需求動態注冊某個服務。Service的調用和實現,核心是BHServiceManager。可以單獨創建Services interface Pod,統一放置要用的Services,這樣的業務依賴就從網狀式變成中心式,業務方只需依賴Services一個。
Service可以動態共享對象,按需加載,BeeHive邏輯是將基礎服務注冊在plist中,業務型服務允許Service不先注冊,直到業務需要時才被動態注冊。
Service支持兩種不同模式:
-
單例: 對于全局統一且無狀態服務,建議使用這種創建形式,這樣有利于Service的統一管理以及減少不必要內存消耗。
-
多實例: 每次調用服務都重新創建新的服務,對于涉及狀態以及狀態變化的服務最適合使用多實例方式。
在多線程環境下遇到了Service讀寫問題,已通過Lock來已避免Array crash問題。
不過Service還存在如下問題:
-
Service依賴關系,導致底層依賴的Service沒有被創建時就被調用。
-
規劃Service、Module創建順序,使得App達到秒開,優化性能體驗。
前者依賴問題計劃通過調度機制來解決,后者還需要將AppDelegate更多業務剝離以及實踐才可,這里不細談。
4. BeeHive背后的思考
BeeHive以一個分發App狀態和統一Service Interface的架構形式解決了多團隊多開發人員協同開發中的耦合問題。對于實踐過程中的開發成本,適應需要一定過程,但邏輯理順后,應用起來不成問題。就收益而言,BeeHive更適合大型的多人項目以及快速移植的項目,小項目使用起來較復雜,有些得不償失。
至此,BeeHive中主體已分析到位,BeeHive是一個正在成長的iOS框架,目前Star已1500+,希望大家可以集思廣益,多提issue、Pull Request,這樣BeeHive也能讓更多人受用。想象一下像蜜蜂一樣優雅地搭建每個蜂窩模塊。
5. 參考
-
Spring相關資料: https://www.ibm.com/developerworks/cn/java/wa-spring1/
-
Apache DSO參考鏈接: http://httpd.apache.org/docs/current/dso.html
-
Cocoapods資料: https://cocoapods.org/
來自:http://mp.weixin.qq.com/s/RUTmeJl4Kh4yXKS1EsYsKw