共计 4281 个字符,预计需要花费 11 分钟才能阅读完成。
组件化是一个陈词滥调的涉及面很广的话题,即不是做好一件事而是做好一系列的事件能力达成;其中蕴含组件化框架在内的各架构层级、构建零碎、依赖管理系统、以及配套的防劣化机制与规定标准。
本文次要基于百度 App 背景、指标和组件化历程来讲述保障并行开发和组件复用的伎俩,尽量避免过多发散到构建零碎、依赖管理系统, 以及组件化框架这样的具体子方向。组件化的重要性取决于利用规模、团队规模、产品技术指标;所述内容尽管是从 iOS 平台登程,但方法论与实现门路实用于大部分平台。
背景与指标
百度 App(大型 App) 复杂度起源
- 业务规模大:百度 App 技术方向及子方向 70+,单端代码量 180w+;
指标:隔离各组件间影响防止故障蔓延,并管制整体 App 的复杂度;
- 团队规模大:有代码权限的数百人 ;
指标:保障高效并行开发;
- 公司外部接入业务多:30+, 非单纯根底库,与百度 App 关系简单;
指标:解决接入业务与百度 App 架构及架构中各组件关系,保障疾速高效接入与根底能力复用。
- 迭代速度快:3 周一个版本,2 周开发 1 周测试;
指标:防止高速迭代状况下组件化水平劣化。
- 技术状态多:H5、NA、Hybrid、Talos、Flutter 并存;
指标:保障根底能力复用,构建零碎撑持。
另外启动速度、体积等准入流程的束缚;以及指标的多样性也是大型 App 复杂度起源因素;由背景产生的指标是天生的技术需要,除此之外,百度 App 在不同阶段有不同的产品技术指标。
百度 App 不同阶段的不同指标
- 单干业务三方库复用 ; 单个技术组件输入 (最早的需要,2014 年), 对单个组件输入来讲,如何防止输入时, 插入萝卜带出 ” 泥 ”;
- 矩阵产品孵化(2017 年~2019);
- 小程序开源复用(2018 年):输入组件兼容不同宿主, 放弃局部依赖组件可替代性;
指标多样性要求在开发时思考到各个指标的诉求,在方案设计时尽量避免和这些指标抵触。
重要架构迭代
初始态 -2013(钻木取火):
这一时期,百度 App 浏览器角色较重,大家都在一个工程里开发,各业务和根底逻辑交织,没有边界,你中有我、我中有你;UI 架构比较复杂,每个 RD 都要从 App 主入口开始看懂主流程代码,小心翼翼的开发。
这一时期的架构是这样:
这一时期的次要问题有:
- 一些根底库、甚至开源三方库都会有业务侵入;没有明确分层和防批改机制,入侵老本极低;
- 首屏各业务间没有容器隔离,牵一发而动全身,极容易相互影响;
- 对各业务共用的服务 (近程配置、端能力) 没有服务组件化,if else/switch case 式逻辑有限蔓延
- 逻辑、资源没有正当归属,数据没有拆分,根底组件对外输入艰难;
- 插件接口层没有体系化建设,稳定性欠佳 (fragile);接入业务成为百度 App 里的超级模块,依赖关系难以管制。
- iOS 开发交换技术群:563513413,不论你是大牛还是小白都欢送入驻,分享 BAT, 阿里面试题、面试教训,探讨技术,大家一起交流学习成长!
2014-2015(蒸汽机时代):
尽管过后团队规模只有几十人,但曾经意识到了组件化的重要性;接入业务逐渐变多,同时也有局部技术组件对外输入的需要;这一阶段:
- 首先拆出三方库,粗粒度拆出根底库,归到业务组件上层;百度 App 和接入业务复用这部分根底库;
- 引入框架容器,对首屏各业务及栈式导航容器中的业务进行隔离;
- 对新兴的业务组件或须要重构的业务,首先采纳组件化模式开发,逻辑、资源、数据各有归属,同时明确内部依赖;
初步制订了依赖标准,禁止层级反向依赖,这一阶段只是标准,没有工具链的强制撑持 ; - 组件除根底库外的依赖通过 Adapter 注入来实现。
这一时期的架构是这样:
这一时期的次要问题有:
组件归属的模糊性, 局部组件游离在根底库和业务组件之间,同层组件间的依赖与调用关系不够清晰;
组件间通过 Adapter 进行一对一解耦,尽管有比拟明确的内部依赖关系,但解耦效率不高 ;
主 App 中还遗留端能力接口,与通过插件零碎接入的一些 SDK。
2016-2017(电力时代)
这一时期重点建设了组件化框架(Pyramid、SchemeRouter)与散发框架 (RemoteConfig、PMS、预取散发),及数据拆分框架(CocoaSetting);进一步保障了各组件能做到逻辑、数据各有归属;
这一时期的架构是这样:
2018-2019(现实态 – 核能时代)
随着百度 App 组件化水平的进步,主工程逐渐壳化,积淀了少量通用服务;这一时期团队高速倒退,退出了多仓库和构建零碎的撑持 (EasyBox)。
这一时期的架构是这样:
这一时期,组件化框架绝对欠缺,各组件已能做到逻辑、资源、数据各有归属。主工程进一步被弱化; - 层级更加明确清晰,游离与根底库层和业务组件层间的通用服务有了归属 ; 组件能够自下而上的对外输入;
- 整个 App 通过地方仓库的组件列表 (Central Repo Specs),通过 EasyBox 组装整个工程;
- 框架容器加载及零碎事件散发对立到轻量级的 AppLauncher;
- 对接入 SDK,按架构层级属性归属;如仅被某一个业务组件援用,则有这个业务组件负责管理,升高对外的复杂度;
- 服务层可共享服务绝对欠缺。
组件化的进阶 – 中台化(星际远航)
中台化的大潮滚滚而来, 除云端一体化复用外,对组件化也提出了其余的更高要求。共享组件库 + 构建零碎 (EasyBox) 合力,已能达到矩阵产品组合输入能力。
组件化的实现门路
自下而上的组件化建设
1、编译隔离、架构分层及层级拜访限度机制建设
- 编译隔离:通过构建零碎(EasyBox)提供的编译规定文件明确每个组件的对外接口,明确组件的内部依赖(这方面 IDE 也常常善意办好事,让组件间能够低成本的随便拜访,逐渐含糊了组件的逻辑边界,加深了组件间的依赖);
- 层间限度:通过构建零碎(EasyBox)建设反向拜访限度,即上层组件不能够拜访下层组件;
- 同层拜访:同层组件间也不能无限度调用,通信及拜访限度通过组件化 Pyramid 框架来实现;各组件间维持较清晰的接口边界和逻辑边界。
2、三方库规范化与根底库体系化 - 根底库次要存在以下问题:
- 没有防批改机制,业务侵入成本低;
- 穿插依赖问题: 同一根底依赖的逻辑归属到同一组件里
根底库要在无业务侵入的状况下通过肯定水平的形象到架构底层,二进制化履行组件负责人制度,并进行体系化建设防止上述问题。 - 三方库次要存在以下问题:
- 没有防批改机制,业务侵入成本低;
- 三方库在肯定用户规模或业务规模下,的确存在 bug,而 github 的 push request 不及时或无响应;
所有三方库更新到最新公布版并二进制化防止业务侵入;差别局部明确批改点,通过运行时独自打补丁;对外输入时,明确这一点。
3、建设运行时候发与隔离服务
为防止各组件对共有逻辑、共有数据集中式解决,建设容器及散发机制来散发事件、数据、以及逻辑调用。 - Pyramid 组件化框架:
- 这里次要讲 Pyramid 框架的散发作用,Pyramid 将零碎事件分发给各子组件;
- 除此之外,组件化框架还有另外两个作用:
1)Pyramid 框架组件间通信:adapter 一对一形式解耦降级为一对多解耦;
2) 它将组件间的强依赖转变为弱依赖,这让技术组件对外输入时,被依赖的组件具备某种程度的可替代性; - 端能力:
- 拆散 SchemeRouter 与 SchemeHandler 逻辑,SchemeRouter 归属服务层组件化框架,SchemeHandler 归属各组件;
- 因为 Scheme 参数不够明确清晰,在百度 App 中 Scheme 次要用于和 H5 的通信,较少用于页面路由;
- 配置散发服务:将集中解析并调用各业务解决逻辑革新为散发机制,并最终降级为云控服务;
- 数据拆分服务:配合配置散发服务,将数据拆分到各组件外部治理;
- 资源 / 预取散发服务:建设资源 / 预取散发服务;
- 框架容器:通过 Tab 导航容器、栈式导航容器将各控制器 UI 数据拆分到各子控制器、事件散发传递给各子控制器;
散发与隔离机制、容器机制是并行开发的重要保障。
4、服务层建设
多业务调用的低依赖组件去业务化形象成通用服务:账号、分享、云控、统计、性能、AI 等
5、建设组件模型
建设组件模型,各业务模块疾速组件化。
- 艰深的讲,就是领导各业务模块明确性能范畴,做到逻辑、资源、数据、公有 SDK 各有归属;
- 最终每个组件是一个独立的性能单元、逻辑单元、数据及资源管理单元,H5 通信单元,性能量化单元,编译输入单元 (1 个或多个)。
- 为了更灵便的组合输入,组件的接口封装层和服务对接层能够进行不同粒度编译单元拆分;次要目标是拆散依赖,满足输入灵活性;
6、业务组件化
依照组件模型,确定业务的性能范畴、逻辑与接口边界,疾速组件化。
7、劣化管制
组件接口变更、依赖变更、Warning 数变动都会记录告诉相干负责人,这些在 Tekes 平台治理;敬请持续关注后续公众号文章;没有防劣化机制,填坑速度永远比不上挖坑速度;一人填坑的速度也永远比不上多人挖坑速度。
收益总结
1. 研发效率的晋升,次要体现在以下几个方面:
- 复杂度管制:复杂度管制在组件外部,对外 ” 简略可依赖 ”;
- 并行开发:组件化框架及各散发服务具备设计时的隔离性,保障大规模并行开发效率;以近程配置为例,原来新增一项开发工夫为 4+ 小时,当初仅需 0.5 小时;效率晋升 8 倍 +;
- 复用:为矩阵产品输入轮子;参考百度 App 矩阵产品,复用率都在 50% 以上;
- 编译速度晋升:因为组件具备独立编译单元的属性, 在编译过程中组件源码和编译产物能够等价替换,所以组件化也为后续组件二进制化打下基础,百度 App 编译速度也平均值从 15 分钟 / 次优化到 2 分钟 / 次;
**2. 品质上,组件化具备设计时的隔离性,确保单个组件的故障影响范畴内敛到本人外部,不会引发整体 crash;
- 为启动速度、体积等方向提供量化单位;
- 建立健全架构体系,分组件深度优化。**
吴军博士在《文化之光》一书中评估希腊人对世界文化的奉献这样写到:近代自然科学的很多体系都是在古希腊时代奠定的,希腊人在学术研究上有别于西方文化之处不在于一两项科学发明和发现,而在于他们将自然科学各学科分门别类,对每一个学科都建设起一整套零碎的体系,在此基础上,演绎或演绎出广泛规律性,即定理或定律,继而成为自然科学各个学科的基石和支柱。
尽管没有这样的高度,但对软件开发来讲,也有殊途同归的作用。
结语
“ 本人 ” 得来终觉浅,援用一段话作为结语,节选自《每个架构师都应该钻研下康威定律》
架构的指标是用于治理复杂性、易变性和不确定性,以确保在长期的零碎演化过程中,一部分架构的变动不会对架构的其它局部产生不必要的负面影响。这样做能够确保业务和研发效率的麻利,让利用的易变局部可能频繁地变动,对利用的其它局部的影响尽可能的小。