BeeHive,一次 iOS 模塊化解耦實踐

z90188043 7年前發布 | 10K 次閱讀 程序員 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核心思想涉及兩個部分:

  1. 各個模塊間調用從直接調用對應模塊,變成調用Service的形式,避免了直接依賴。

  2. 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. 參考

  1. Spring相關資料: https://www.ibm.com/developerworks/cn/java/wa-spring1/

  2. Apache DSO參考鏈接: http://httpd.apache.org/docs/current/dso.html

  3. Cocoapods資料: https://cocoapods.org/

 

來自:http://mp.weixin.qq.com/s/RUTmeJl4Kh4yXKS1EsYsKw

 

 本文由用戶 z90188043 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!