原創:GuoJin 百度APP技術團隊-資深技術專家 文章來源:百度APP技術微信公衆號
git
組件化是一個老生常談的涉及面很廣的話題,即不是作好一件事而是作好一系列的事情才能達成;其中包含組件化框架在內的各架構層級、構建系統、依賴管理系統、以及配套的防劣化機制與規則規範。
本文主要基於百度App背景、目標和組件化歷程來說述保障並行開發和組件複用的手段,儘可能避免過多發散到構建系統、依賴管理系統,以及組件化框架這樣的具體子方向。組件化的重要性取決於應用規模、團隊規模、產品技術目標;所述內容雖然是從iOS平臺出發,但方法論與實現路徑適用於大部分平臺。github
背景與目標
百度App(大型App)複雜度來源
- 業務規模大:百度App技術方向及子方向70+,單端代碼量180w+;
目標:隔離各組件間影響避免故障蔓延,並控制總體App的複雜度;
- 團隊規模大:有代碼權限的數百人;
目標:保障高效並行開發;
- 公司內部接入業務多:30+,非單純基礎庫,與百度App關係複雜;
目標:處理接入業務與百度App架構及架構中各組件關係,保障快速高效接入與基礎能力複用。
- 迭代速度快:3週一個版本,2周開發1周測試;
目標:避免高速迭代狀況下組件化程度劣化。
- 技術形態多:H五、NA、Hybrid、Talos、Flutter並存;
目標:保障基礎能力複用,構建系統支撐。
另外啓動速度、體積等准入流程的約束;以及目標的多樣性也是大型App複雜度來源因素;由背景產生的目標是天生的技術需求,除此以外,百度App在不一樣階段有不一樣的產品技術目標。小程序
百度App不一樣階段的不一樣目標
- 合做業務三方庫複用;單個技術組件輸出(最先的需求,2014年),對單個組件輸出來說,如何避免輸出時,拔出蘿蔔帶出"泥";
- 矩陣產品孵化(2017年~2019);
- 小程序開源複用(2018年):輸出組件兼容不一樣宿主,保持部分依賴組件可替代性; 目標多樣性要求在開發時考慮到各個目標的訴求,在方案設計時儘可能避免和這些目標衝突。
重要架構迭代
初始態-2013(鑽木取火):
這一時期,百度App瀏覽器角色較重,你們都在一個工程裏開發,各業務和基礎邏輯交錯,沒有邊界,你中有我、我中有你;UI架構比較複雜,每一個RD都要從App主入口開始看懂主流程代碼,當心翼翼的開發。
這一時期的架構是這樣: 瀏覽器
這一時期的主要問題有:微信
- 一些基礎庫、甚至開源三方庫都會有業務侵入;沒有明確分層和防修改機制,入侵成本極低;
- 首屏各業務間沒有容器隔離,牽一髮而動全身,極容易互相影響;
- 對各業務共用的服務(遠程配置、端能力)沒有服務組件化,if else/switch case式邏輯無限蔓延;
- 邏輯、資源沒有合理歸屬,數據沒有拆分,基礎組件對外輸出困難;
- 插件接口層沒有體系化建設,穩定性欠佳(fragile);接入業務成爲百度App裏的超級模塊,依賴關係難以控制。
2014-2015(蒸汽機時代):
雖然當時團隊規模只有幾十人,但已經意識到了組件化的重要性;接入業務逐步變多,同時也有部分技術組件對外輸出的需求;這一階段:架構
- 首先拆出三方庫,粗粒度拆出基礎庫,歸到業務組件下層;百度App和接入業務複用這部分基礎庫;
- 引入框架容器,對首屏各業務及棧式導航容器中的業務進行隔離;
- 對新興的業務組件或須要重構的業務,首先採用組件化模式開發,邏輯、資源、數據各有歸屬,同時明確外部依賴;
- 初步制定了依賴規範,禁止層級反向依賴,這一階段只是規範,沒有工具鏈的強制支撐;
- 組件除基礎庫外的依賴經過Adapter注入來實現。
這一時期的架構是這樣: 框架
這一時期的主要問題有:
- 組件歸屬的模糊性,部分組件遊離在基礎庫和業務組件之間,同層組件間的依賴與調用關係不夠清晰;
- 組件間經過Adapter進行一對一解耦,雖然有比較明確的外部依賴關係,但解耦效率不高;
- 主App中還遺留端能力接口,與經過插件系統接入的一些SDK。
2016-2017(電力時代)
這一時期重點建設了組件化框架(Pyramid、SchemeRouter)與分發框架(RemoteConfig、PMS、預取分發),及數據拆分框架(CocoaSetting);進一步保障了各組件能作到邏輯、數據各有歸屬;
工具
這一時期的架構是這樣: 組件化
2018-2019(理想態-核能時代)
這一時期,組件化框架相對完善,各組件已能作到邏輯、資源、數據各有歸屬。
主工程進一步被弱化;
- 層級更加明確清晰,遊離與基礎庫層和業務組件層間的通用服務有了歸屬;組件能夠自下而上的對外輸出;
- 整個App經過中央倉庫的組件列表(Central Repo Specs),通過EasyBox組裝整個工程;
- 框架容器加載及系統事件分發統一到輕量級的AppLauncher;
- 對接入SDK,按架構層級屬性歸屬;如僅被某一個業務組件引用,則有這個業務組件負責管理,下降對外的複雜度;
- 服務層可共享服務相對完善。
組件化的進階-中臺化(星際遠航)
中臺化的大潮滾滾而來,除雲端一體化複用外,對組件化也提出了其餘的更高要求。共享組件庫+構建系統(EasyBox)協力,已能達到矩陣產品組合輸出能力。 性能
組件化的實現路徑
自下而上的組件化建設
一、編譯隔離、架構分層及層級訪問限制機制創建
- 編譯隔離:經過構建系統(EasyBox)提供的編譯規則文件明確每一個組件的對外接口,明確組件的外部依賴(這方面IDE也常常好心辦壞事,讓組件間能夠低成本的隨意訪問,逐步模糊了組件的邏輯邊界,加深了組件間的依賴);
- 層間限制:經過構建系統(EasyBox)創建反向訪問限制,即下層組件不能夠訪問上層組件;
- 同層訪問:同層組件間也不能無限制調用,通訊及訪問限制經過組件化Pyramid框架來完成;各組件間維持較清晰的接口邊界和邏輯邊界。
二、三方庫規範化與基礎庫體系化
1)基礎庫主要存在如下問題:
- 沒有防修改機制,業務侵入成本低;
- 交叉依賴問題:同一基礎依賴的邏輯歸屬到同一組件裏;
基礎庫要在無業務侵入的狀況下通過必定程度的抽象到架構底層,二進制化實行組件負責人制度,並進行體系化建設避免上述問題。
2)三方庫主要存在如下問題:
- 沒有防修改機制,業務侵入成本低;
- 三方庫在必定用戶規模或業務規模下,確實存在bug,而github的push request不及時或無響應;
全部三方庫更新到最新發布版並二進制化避免業務侵入;差別部分明確修改點,經過運行時單獨打補丁;對外輸出時,明確這一點。
三、創建運行時分發與隔離服務
爲避免各組件對共有邏輯、共有數據集中式處理,創建容器及分發機制來分發事件、數據、以及邏輯調用。
Pyramid組件化框架:
- 這裏主要講Pyramid框架的分發做用,Pyramid將系統事件分發給各子組件;
- 除此以外,組件化框架還有另外兩個做用:
1)Pyramid框架組件間通訊:adapter一對一方式解耦升級爲一對多解耦;
2)它將組件間的強依賴轉變爲弱依賴,這讓技術組件對外輸出時,被依賴的組件具備某種程度的可替代性;
端能力:
- 分離SchemeRouter與SchemeHandler邏輯,SchemeRouter歸屬服務層組件化框架,SchemeHandler歸屬各組件;
- 因爲Scheme參數不夠明確清晰,在百度App中Scheme主要用於和H5的通訊,較少用於頁面路由;
配置分發服務:將集中解析並調用各業務處理邏輯改造爲分發機制,並最終升級爲雲控服務;
數據拆分服務:配合配置分發服務,將數據拆分到各組件內部管理;
資源/預取分發服務:創建資源/預取分發服務;
框架容器:經過Tab導航容器、棧式導航容器將各控制器UI數據拆分到各子控制器、事件分發傳遞給各子控制器;
分發與隔離機制、容器機制是並行開發的重要保障。
四、服務層創建
多業務調用的低依賴組件去業務化抽象成通用服務:帳號、分享、雲控、統計、性能、AI等
五、創建組件模型
創建組件模型,各業務模塊快速組件化。
- 通俗的講,就是指導各業務模塊明確功能範圍,作到邏輯、資源、數據、私有SDK各有歸屬;
- 最終每一個組件是一個獨立的功能單元、邏輯單元、數據及資源管理單元,H5通訊單元,性能量化單元,編譯輸出單元(1個或多個)。
- 爲了更靈活的組合輸出,組件的接口封裝層和服務對接層能夠進行不一樣粒度編譯單元拆分;主要目的是分離依賴,知足輸出靈活性;
六、業務組件化 按照組件模型,肯定業務的功能範圍、邏輯與接口邊界,快速組件化。
七、劣化控制 組件接口變動、依賴變動、Warning數變化都會記錄通知相關負責人,這些在Tekes平臺管理;敬請繼續關注後續公衆號文章;沒有防劣化機制,填坑速度永遠比不上挖坑速度;一人填坑的速度也永遠比不上多人挖坑速度。
收益總結
1.研發效率的提高,主要體如今如下幾個方面:
- 複雜度控制:複雜度控制在組件內部,對外"簡單可依賴";
- 並行開發:組件化框架及各分發服務具有設計時的隔離性,保障大規模並行開發效率;以遠程配置爲例,原來新增一項開發時間爲4+小時,如今僅需0.5小時;效率提高8倍+;
- 複用:爲矩陣產品輸出輪子;參考百度App矩陣產品,複用率都在50%以上;
- 編譯速度提高:由於組件具備獨立編譯單元的屬性,在編譯過程當中組件源碼和編譯產物能夠等價替換,因此組件化也爲後續組件二進制化打下基礎,百度App編譯速度也平均值從15分鐘/次優化到2分鐘/次;
2.質量上,組件化具有設計時的隔離性,確保單個組件的故障影響範圍內斂到本身內部,不會引起總體crash;
3.爲啓動速度、體積等方向提供量化單位;
4.創建健全架構體系,分組件深度優化。
吳軍博士在《文明之光》一書中評價希臘人對世界文明的貢獻這樣寫到:近代天然科學的不少體系都是在古希臘時代奠基的,希臘人在學術研究上有別於東方文明之處不在於一兩項科學發明和發現,而在於他們將天然科學各學科分門別類,對每個學科都創建起一整套系統的體系,在此基礎上,演繹或概括出廣泛規律性,即定理或定律,繼而成爲天然科學各個學科的基石和支柱。
雖然沒有這樣的高度,但對軟件開發來說,也有殊途同歸的做用。
結語
"本身"得來終覺淺,引用一段話做爲結語,節選自《每一個架構師都應該研究下康威定律》
架構的目標是用於管理複雜性、易變性和不肯定性,以確保在長期的系統演化過程當中,一部分架構的變化不會對架構的其它部分產生沒必要要的負面影響。這樣作能夠確保業務和研發效率的敏捷,讓應用的易變部分可以頻繁地變化,對應用的其它部分的影響儘量的小。
參考