| |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
-> 移动开发 -> Alibaba iOS 工程架构腐化治理实践 -> 正文阅读 |
|
[移动开发]Alibaba iOS 工程架构腐化治理实践 |
背景近年来,iOS工程复杂度高的负面影响逐渐暴露,很多同学都受到了iOS打包慢和打包复杂的“摧残”,业务开发效率受到很大影响。我记得曾经有个同学跟我诉苦,他把几个模块打包后集成到主工程,这个过程中每个步骤都有打包失败,总共花了大半天时间。 Alibaba.com是跨境B类电商业务,2012年开始开发iOS客户端。为了支撑业务发展,2016年进行组件化改造,从单一工程架构演化模块化架构。随着业务和无线技术的发展,客户端已经从小型模块化工程演化为一个巨无霸工程。团队一共建设了100多个自维护模块,包括业务模块、架构设施、Hybrid容器、Flutter容器、动态化技术、基础中间件等能力。表面上工程架构正在有序地演进,但内部已经乱象丛生。模块关系混乱,循环依赖和反向依赖行为越来越多。大量模块不符合LLVM Module标准,spec文件不全、头文件引用不规范。因为工程不规范,Cocoapods无法升级,只能使用1.2和1.5旧版本,技术上落后了3年以上。 为了彻底解决问题,提高业务开发体验,阿里巴巴ICBU端架构组对iOS工程架构进行全面地治理。我也写下一篇文章记录自己的思考,欢迎有兴趣的同学指导交流。
架构腐化会产生哪些问题?问题一:模块打包复杂度高 1?工程环境混杂 2016年Alibaba客户端组件化做的并不彻底,很多模块只是形式上的分离,实际上还存在反向依赖和循环依赖问题。到了2017年,团队想做Framework化,发现模块单独打包编译不过。于是,为了模块编译通过,我们开发兼容脚本,将所有framwwork和头文件都添加到工程searchPath里,并且让模块直接读取同步主工程Profile里所有依赖。自从有了兼容逻辑,spec文件不写依赖描述也能编译得过,于是再也没人维护spec文件,跨模块的头文件引用也越写越乱。 2环境不兼容&模块构建失败 因为存在循环依赖、头文件不规范等问题,模块编译脚本加了许多workaround逻辑,兼容头文件索引。这导致模块Cocoapods环境无法升级,一直停留在1.2版本。而随着中间件和社区swift技术越来越多,主工程Podfile用了cocoapod 1.5的新语法。环境开始不兼容。同时,模块解析主工程Podfile时,无法识别cocoapod 1.5的新语法,模块构建失败。 3每年浪费了90人日的开发资源 模块打包失败后,开发需要分析日志,排查打包失败原因,若分析不出来则需要找架构组支持。一个模块打包失败,会一直卡住需求不能集成,会阻塞测试或其他开发工作。 根据开发反馈的情况,估计平均一次模块打包失败要消耗2个小时的研发资源。据统计,Q1期间,模块打包失败总数高达200多次,其中70%的打包失败是因为复杂度过高导致的。每一次打包失败浪费2个小时,相当于每年浪费了90人日的研发资源。
问题二:主工程打包慢 如果模块不规范,又需要引用swift中间件,无法独立静态库,只能以源码形式集成到主工程。这导致主工程打包时需要编译大量源码,平均打包时间比手淘、优酷等工程慢12分钟。需求提测、集成、修复bug、排查问题时都需要进行主工程打包,打包慢会阻塞开发和测试的工作。某一次双周迭代打包了70次,浪费了14个小时。 问题三:工程环境不稳定 Cocoapods环境不能升级,只能使用1.2和1.5的旧版本。但旧版本环境没人维护,环境极其脆弱,比如有人发布了一个不合法的spec,Pod Update就会挂掉。因为模块不规范,源码开发时会出现各种莫名其妙的编译问题。业务开发和调试效率会很低,浪费大量的时间。 问题四:Swift开发寸步难行 近几年swift普及,iOS社区和集团swift中间件越来越多。然而,Swift模块严格遵守“LLVM Modules”规范,不允许循环依赖、外部依赖要显示声明、头文件引用要采用尖括号,否则就会出现“could not build module xxx”、“No such module”等错误。高标准的要求下,我们的工程开发引入Swift寸步难行。虽然我们自己可以不使用Swift,但集团和三方的中间件Swift化的趋势是不可逆的。 近两年,Alibaba.com的工程引入许多Swift中间件,同时也自主研发了许多swift组件,这也彻底引爆了研发效率的问题。相关模块频繁打包异常。不规范问题错综复杂,经常解决完一个编译器错误,又出现另一个错误,子子孙孙无法穷尽。最后系统开始出现各种不可控风险。 此外我们大部分模块都不符合LLVM Modules规范。如果业务需求使用Swift或引用到Swift中间件,就要花大量时间去解决适配问题。根据敏捷迭代的数据,需求A计划10人日,实际消耗20人日,需求B计划6人日,实际消耗10人日。
问题五:历史代码清理困难 最近几年很多旧业务已经下线或改造。但因为模块之间耦合严重,许多旧代码一直不敢删,这也导致包大小持续膨胀。 架构腐化治理的困难与策略1影响范围广,治理难推动 2020年,我在iOS技术栈发起了架构治理项目,发动各个业务线的iOS开发一起治理,却陷入了困局。一方面,业务开发没有投入资源。另一方面,许多业务模块之间调用关系混乱,治理风险高,大家都不敢随便动。 2数据化分析,自顶向下推动 iOS工程的混乱已经严重影响了业务发展,大家时间都浪费在解决编译打包问题上。各业务的iOS开发同学都被困扰,许多开始反馈因为打包困难严重影响开发效率。 为此,我开始全面梳理研发流程的数据。一方面,我统计了模块构建失败数据,主工程打包的耗时,然后再结合其他客户端的数据进行对比;另一方面,我对业务开发做访谈,从用户的角度了解资源浪费的数据,补充研发平台中无法统计到的环节。最后,成功将工程混乱对研发效率的负面影响量化为具体的数据。 有了数据分析结果,就有了推动的抓手,可以自顶向下推进架构治理。 解决方案纵观全局,理清模块依赖关系 第一个难点是模块的关系不清晰。模块描述文件里依赖列表都是空的,模块之间的关系就像一团毛线。 模块的关系不清晰,治理项目就无法拆解,成本也估算不出来。因此要先纵观全局,分析整体的模块依赖关系。 我开发了一个工具进行分析。首现查找模块的所有文件,使用正则匹配找到它import的外部头文件,得到外部引用的头文件集合。然后搜索主工程的Pods目录,匹配头文件所属的外部模块,最后聚合得到完整的模块依赖树。 下一步是视觉化,视觉化以后可以更直观地查看模块关系的复杂度,方便制定治理计划。我使用了Dot language来描述模块关系,可以自动生成整个工程的依赖关系图,也可以生成某个特定模块的依赖关系图。 依赖倒置、分层治理 第二个难点是治理的依赖条件复杂。 模块治理成功的标准是整个依赖树的所有模块都没有循环依赖,并且都符合LLVM Module规范。比如治理业务模块A,模块A的依赖树里有一个模块C,模块C存在循环依赖或不符合Module规范,A模块打包时就会报异常.而Cocoapod和XCode每次只报一个异常,不能分析整个依赖树所有的问题。 我们工程自己维护的模块有130多个,三方库和中间件模块200多个。业务模块除了自身依赖,还有许多间接依赖,依赖树非常复杂。这种情况下,直接治理业务模块复杂度极高,治理过程也会很混乱。 上图的示例中,模块C、模块I、模块G是关系复杂的中心模块。比如“模块I”直接依赖了30个外部模块,间接依赖100多个模块,它直接耦合关系有5个循环,间接耦合关系15+个循环。如果直接治理“模块I”,需要解耦15个循环关系,将100多个模块进行Module化改造。按照这样的思路治理,修改逻辑极其复杂,很可能治理到一半就进行不下去。 为了解决这个困局,我对模块进行分层和分类。划分的基础逻辑有3个:
按照这个思路,我先梳理清楚模块所属的层次,然后自底层逐层向上治理。当底层模块都治理完,依赖多的模块负担也会大大降低。当底层的循环依赖解耦完成,上层的模块就不用处理的间接循环依赖。 最后使用四象限分析法,将模块分为4个组,1基础模块无循环依赖、2基础模块有循环依赖、3业务模块无循环依赖、4业务模块有循环依赖,按顺序治理每一组。 自动化修复 第三个难点是代码改动量大。模块治理面临许多子问题,“模块spec文件的依赖描述不全”、“umbralla头文件不缺失”、“public头文件引用不规范”、“循环依赖解耦”。仅仅修复“模块spec文件的依赖描述不全”就很困难。 补全依赖的方法是查找所有源文件的import描述“(import <xxxFramework/xxx.h)”,统计以来的所有framework。再基于framework名称反向查找所属的模块。另外有很多import格式不规范,有些是直接引用文件名(import “xxx.h”),有些是路径方式引用(import <xxx/xxx/xxx.h>),遇到这种不规范的引用,还需要全局搜索才能找到属于哪个模块。举个例子,模块A的dependence描述是空的,但实际上它依赖了20几个模块。模块A有60多个源文件,每个源文件import引用平均是10行,总共600行引用代码。如果人工分析这600行代码,估计得花一天时间。这还只是修改其中一个问题,还不包括“umbralla头文件不缺失”、“public头文件引用不规范”、“循环依赖解耦”。 因此,纯人工治理根本行不通,必须通过自动化的方式提高效率。于是我开发了一个架构管理引擎,可以用来分析模块依赖关系,也可以修复spec依赖描述不全、自动生成umbralla头文件、修改不规范头文件引用等等。自动化的修复工具可以覆盖95%的代码改动量,开发只负责修改路由、服务API、代码迁移、模块拆分合并等变化较大的逻辑改动。 架构管理引擎不仅可以做架构治理,它还能做为团队管理工具,比如分析git仓库活跃度,批量设置CodeReview规则,记录研发过程的日志。 下面这段代码使用了ruby语言和cocoapods-core框架,主要功能是分析模块import代码,修复模块的podspec的依赖。
架构和业务合作治理 第四个难点是解耦涉及大量业务逻辑。很多代码是业务的分支逻辑,重构后很难测试,如果不全面验证很容易出线上故障。 解耦涉及大量业务逻辑,降低风险最好的方法是交给业务开发来修改。因此架构组牵头了横向的iOS工程治理项目,架构组提供治理方案和工具,业务开发负责业务逻辑解耦。业务解耦采用了4种方式,路由Scheme、服务化API、公共组件下沉、模块合并。 举几个典型的解耦场景: 场景一,产品模块里有一个子业务是产品推荐,订单模块也需要用到,于是订单模块会反向依赖产品模块,形成循环关系。这种场景解耦的方式是从产品模块中拆分出基础组件,订单模块依赖基础组件。 场景二,产品模块跳转订单模块时使用产品的model作为API的入参,订单模块为了引用产品的model,反向依赖了产品模块。这种场景解耦的方式是使用路由URL Scheme协议,将model转化为URL中query的入参。 长效保障机制 进行架构治理后,模块的循环依赖和modula规范等问题得到解决,但今后可能出现二次腐化。我们当然不希望隔一段时间又要重新治理,于是从架构设计和研发流程的卡口入手,优化架构和流程,杜绝后续的二次腐化。 1?架构优化
2收敛模块工程 如果模块各自维护构建工程,长期维护必然导致构建配置有很大差异。一方面,这样不能统一升级构建配置,架构治理和技术升级的成本会很高;另一方面,模块如果出现构建问题,排查成本也会变高。 因此,我们建设了打包脚本,每次打包动态生成模块工程。模块不再维护独立工程,构建配置统一收敛到podspec文件。 模块打包时,动态创建模块的构建工程
3CocoaPod和Xcode编译卡口
4Devops构建卡口
总结架构腐化就像“流感病毒”,它的负面影响很难被感知和量化。 对于技术团队而言,要避免架构腐化,技术团队要对技术有更高的敬畏,相比于等大火蔓延再就抢救,我们应该对及时灭火的人给与更多实质性的支持和鼓励。 对于架构师而言,需要架构师能熟练开发工具。面对复杂的度架构问题,首现要进行全面分析,对系统问题进行拆解,找到复杂度最低的治理路径,并有意识地寻找数据支撑,获得团队的支持。 最后,从架构治理的角度。客户端工程是天然中心化架构,它很容易因为环境冲突导致编译问题。因此,我们设计组件化架构时,要确保模块的环境完全独立,避免出现中心化架构。架构治理不是终点,治理完成后要有防止腐化的机制,避免出现二次腐化。 参考
我们招聘啦! Alibaba.com 是全球最大的B类国际化电商平台,长期招牌端架构、直播、短视频、IM、电商等领域的技术人才。如果你对iOS、Android、Flutter等移动技术充满热情,欢迎加入Alibaba.com客户端研发团队,可以Base杭州和深圳。 简历投至方式 联系邮箱:blacktea.hw@alibaba-inc.com 微信号:blackteachinese 《Cube 技术解读 | 支付宝新一代动态化技术架构与选型综述》 关注我们,每周 3 篇移动干货&实践给你思考! |
|
移动开发 最新文章 |
Vue3装载axios和element-ui |
android adb cmd |
【xcode】Xcode常用快捷键与技巧 |
Android开发中的线程池使用 |
Java 和 Android 的 Base64 |
Android 测试文字编码格式 |
微信小程序支付 |
安卓权限记录 |
知乎之自动养号 |
【Android Jetpack】DataStore |
|
上一篇文章 下一篇文章 查看所有文章 |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 | -2024/11/27 12:08:09- |
|
网站联系: qq:121756557 email:121756557@qq.com IT数码 |