“ 业务开发遇到环境问题越来越多,严重影响开发效率,有些表面看似打包问题,背后却是工程架构的腐化。”
背景
近年来,iOS工程复杂度高的负面影响逐渐暴露,很多同学都受到了iOS打包慢和打包复杂的“摧残”,业务开发效率受到很大影响。我记得曾经有个同学跟我诉苦,他把几个模块打包后集成到主工程,这个过程中每个步骤都有打包失败,总共花了大半天时间。
Alibaba.com是跨境B类电商业务,2012年开始开发iOS客户端。为了支撑业务发展,2016年进行组件化改造,从单一工程架构演化模块化架构。随着业务和无线技术的发展,客户端已经从小型模块化工程演化为一个巨无霸工程。团队一共建设了100多个自维护模块,包括业务模块、架构设施、Hybrid容器、Flutter容器、动态化技术、基础中间件等能力。表面上工程架构正在有序地演进,但内部已经乱象丛生。模块关系混乱,循环依赖和反向依赖行为越来越多。大量模块不符合LLVM Module标准,spec文件不全、头文件引用不规范。因为工程不规范,Cocoapods无法升级,只能使用1.2和1.5旧版本,技术上落后了3年以上。
为了彻底解决问题,提高业务开发体验,阿里巴巴ICBU端架构组对iOS工程架构进行全面地治理。我也写下一篇文章记录自己的思考,欢迎有兴趣的同学指导交流。
Steve Mcconnell 《Code Complete》:“软件的首要技术使命:管理复杂度。”
架构腐化会产生哪些问题?
问题一:模块打包复杂度高
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人日的研发资源。
Robert Martin 《Clean Architecture》:“不管你们多敬业,加多少班,在面对烂系统时,你仍然会寸步难行,因为你的大部分精力不是在应对开发需求,而是在应对混乱。”
问题二:主工程打包慢
如果模块不规范,又需要引用swift中间件,无法独立静态库,只能以源码形式集成到主工程。这导致主工程打包时需要编译大量源码,平均打包时间比手淘、优酷等工程慢12分钟。需求提测、集成、修复bug、排查问题时都需要进行主工程打包,打包慢会阻塞开发和测试的工作。某一次双周迭代打包了70次,浪费了14个小时。
问题三:工程环境不稳定
Cocoapods环境不能升级,只能使用1.2和1.5的旧版本。但旧版本环境没人维护,环境极其脆弱,比如有人发布了一个不合法的spec,Pod Update就会挂掉。因为模块不规范,源码开发时会出现各种莫名其妙的编译问题。业务开发和调试效率会很低,浪费大量的时间。
问题四:Swift开发寸步难行
近几年swift普及,iOS社区和集团swif