随着各业务的蓬勃发展,大众点评移动研发团队从当初各自为战的“小作坊”已经发展成为可以协同作战的、拥有千人规模的“正规军”。我们的移动项目架构为了适应业务发展也发生了天翻地覆的变化,这对移动持续集成提出更高的要求,而整个移动研发团队也迎来了新的机遇和挑战。
当前移动客户端的组件库超过600个,多个移动项目的代码量达到百万行级别,每天有几百次的发版集成需求。保证近千名移动研发人员顺利进行开发和集成,这是我们部门的重要使命。但是,前进的道路从来都不是平坦的,在通向目标的大道上,我们还面临着很多问题与挑战。
项目依赖复杂、研发流程琐碎、构建速度慢、App质量保证是每个移动项目在团队、业务发展壮大过程中都会遇到的问题,本场 Chat 将根据大众点评移动端多年来积累的实践经验,一步步阐述我们是如何在实战中解决这些问题的。
作者简介:
智聪,大众点评 iOS 技术专家,专注于移动工具链开发,对移动持续集成、静态分析平台建设有深刻理解和丰富的实践经验。
邢轶,大众点评 Android 技术专家,专注于移动持续集成、静态分析、静态化等 App 基础设施建设。
大众点评移动研发中心,Base上海,为美团提供移动端底层基础设施服务,包含网络通信、移动监控、推送触达、动态化引擎、移动研发工具等。同时团队还承载流量分发、UGC、内容生态、个人中心等业务研发工作,长年虚位以待专注于移动端研发的各路英雄豪杰。欢迎投递简历:[email protected]。
美团是全球最大的互联网 + 生活服务平台,为 3.2 亿活跃用户和 500 多万的优质商户提供一个连接线上与线下的电子商务服务。秉承 “ 帮大家吃得更好,生活更好 ” 的使命,我们的业务覆盖了超过 200 个品类和 2800 个城区县网络,在餐饮、外卖、酒店旅游、丽人、家庭、休闲娱乐等领域具有领先的市场地位。
随着各业务的蓬勃发展,大众点评移动研发团队从当初各自为战的 “ 小作坊 ” 已经发展成为可以协同作战的、拥有千人规模的 “ 正规军 ”。
我们的移动项目架构为了适应业务发展也发生了天翻地覆的变化,这对移动持续集成提出更高的要求,而整个移动研发团队也迎来了新的机遇和挑战。
当前移动客户端的组件库超过 600 个,多个移动项目的代码量达到百万行级别,每天有几百次的发版集成需求。
保证近千名移动研发人员顺利进行开发和集成,这是我们部门的重要使命。但是,前进的道路从来都不是平坦的,在通向目标的大道上,我们还面临着很多问题与挑战,主要包括以下几个方面:
上图仅仅展示了我们移动项目中一小部分组件间的依赖关系,可以想象一下,这 600 多个组件之间的依赖关系,就如同一个城市复杂的道路交通网让人眼花缭乱。
这种组件间错综复杂的依赖关系也必然会导致两个严重的问题。
第一,如果某个业务需要修改代码,极有可能会影响到其它业务,牵一发而动全身,进而会让很多研发同学工作时战战兢兢,做项目更加畏首畏尾;
第二,管理这些组件间繁琐的依赖关系也是一件令人头疼的事情,现在平均每个组件的依赖数有 70 多个,最多的甚至达到了 270 多个,如果依靠人工来维护这些依赖关系,难如登天。
移动研发要完成一个完整功能需求,除了代码开发以外,需要经历组件发版、组件集成、打包、测试。如果测试发现 Bug 需要进行修复,然后再次经历组件发版、组件集成、打包、测试,直到测试通过交付产品。
研发同学在整个过程中需要手动提交 MR、手动升级组件、手动触发打包以及人工实时监控流程的状态,如此研发会被频繁打断来跟踪处理过程的衔接,势必严重影响开发专注度,降低研发生产力。
目前大众点评的 iOS 项目构建时间,从两年前的 20 分钟已经增长到现在的 60 分钟以上,Android 项目也从 5 分钟增长到 11 分钟,移动项目构建时间的增长,已经严重影响了移动端开发集成的效率。而且随着业务的快速扩张,项目代码还在持续不断的增长。
为了适应业务的高速发展,寻求行之有效的方法来加快移动项目的构建速度,已经变得刻不容缓。
评价 App 的性能质量指标有很多,例如:CPU 使用率、内存占用、流量消耗、响应时间、线上 Crash 率、包体等等。其中线上 Crash 直接影响着用户体验,当用户使用 App 时如果发生闪退,他们很有可能会给出 “ 一星 ” 差评;而包体大小是影响新用户下载 App 的重要因素,包体过大用户很有可能会对你的 App 失去兴趣。
因此,降低 App 线上 Crash 率以及控制 App 包体大小是每个移动研发都要追求的重要目标。
项目依赖复杂、研发流程琐碎、构建速度慢、App 质量保证是每个移动项目在团队、业务发展壮大过程中都会遇到的问题,本文将根据大众点评移动端多年来积累的实践经验,一步步阐述我们是如何在实战中解决这些问题的。
MCI(Mobile continuous integration)是大众点评移动端团队多年来实践总结出来的一套行之有效的架构体系。
它能实际解决移动项目中依赖复杂、研发流程琐碎、构建速度慢的问题,同时接入 MCI 架构体系的移动项目能真正有效实现 App 质量的提升。
MCI 完整架构体系如下图所示:
MCI 架构体系包含移动 CI 平台、流程自动化建设、静态检查体系、日志监控 & 分析、信息管理配置,另外 MCI 还采取二进制集成等措施来提升 MCI 的构建速度。
我们通过构建移动 CI 平台,来保证移动研发在项目依赖极其复杂的情况下,也能互不影响完成业务研发集成;其次我们设计了合理的 CI 策略,来帮助移动研发人员走出令人望而生畏的依赖关系管理的“泥潭”。
在构建移动 CI 平台的基础上,我们对 MCI 流程进行自动化建设来解决研发流程琐碎问题,从而解放移动研发生产力。
在 CI 平台保证集成正确性的情况下,我们通过依赖扁平化以及优化集成方式等措施来提升 MCI 的构建速度,进一步提升研发效率。
我们建立一套完整自研的静态检查体系,针对移动项目的特点,MCI 上线全方位的静态检查来促进 App 质量的提升。
我们对 MCI 体系的完整流程进行日志落地,方便问题的追溯与排查,同时通过数据分析来进一步优化 MCI 的流程以及监控移动 App 项目的健康状况。
最后,为了方便管理接入 MCI 的移动项目,我们建设了统一的项目信息管理配置平台。
接下来,我们将依次详细探讨 MCI 架构体系是如何一步步建立,进而解决我们面临的各种问题。
我们对目前业内流行的 CI 系统,如:Travis CI、 CircleCI、Jenkins、Gitlab CI 调研后,针对移动项目的特点,综合考虑代码安全性、可扩展性及页面可操作性,最终选择基于 Gitlab CI 搭建移动持续集成平台,当然我们也使用 Jenkins 做一些辅助性的工作。
MCI体系的CI核心架构如下图所示:
名词解释:
该架构的优势是可扩展性强、可定制、支持并发。首先 CI 服务器可以任意扩展,除了专用的服务器可以作为 CI 服务器,普通个人 PC 机也可以作为 CI 服务器(缺点是性能比服务器差,任务执行时间较长);其次每个集成任务的 Pipeline 是支持可定制的,托管在 MCI 的集成项目可以根据自身需求定制与之匹配的 Pipeline;最后,每个集成项目的任务执行是可并发的,因此各业务线间可以互不干扰的进行组件代码集成。
一次完整的组件集成流程包含两个阶段:组件库发版和向目标 App 工程集成。如下图所示:
第一阶段,在日常功能开发完毕后,研发提 PR 到指定分支,在对代码进行 Review、组件库编译及静态检查无误后,自动发版进入组件池中。所有进入组件池中的组件均可以在不同 App 项目中复用。
第二阶段,研发根据需要将组件合入指定 App 工程。组件 A 本身的正确性已经在第一阶段的组件库发版中验证,第二阶段是检查组件 A 的改变是否对目标 App 中原有依赖它的其它组件造成影响。所以首先需要分析组件 A 被目标 App 中哪些组件所依赖,目标 App 工程按照各自的准入标准,对合入的组件库进行编译和静态分析,待检查无误后,最终合入发布分支。
通过组件发版和集成两阶段的CI流程,组件将被正确集成到目标项目中。而对于存在问题的组件则会阻挡在项目之外,因此不会影响其它业务的正常开发和发版集成,各业务研发流程独立可控。
组件的发版和集成能否通过 CI 检查,取决于组件当前的依赖以及组件本身是否与目标项目兼容。移动研发需要对组件当前依赖有足够的了解才能顺利完成发版集成,为了减小组件依赖管理的复杂度,我们设计了合理的发版集成策略来帮助移动研发走出繁琐的版本依赖管理的困境。
每个组件都有自己的依赖项,不同组件可能会依赖同一个组件,组件向目标项目集成过程中会面临如下一些问题:
频繁的版本集成冲突会导致业务协同开发集成效率低下,App 测试包的不稳定性会给研发追踪问题带来极大的困扰。问题的根源在于目标项目使用每个组件的依赖项来进行集成。因此我们通过在集成项目中显示指定组件版本号以及禁止动态依赖的方式,保证了 App 测试包的稳定性和可靠性,同时也解决了组件版本集成冲突问题。
组件向组件池发版也一样会涉及依赖项的管理,简单粗暴的方法是指定所有依赖项的版本号,这样做的好处是直观明了,但研发需要对不同版本依赖项的功能有足够的了解。正如组件集成策略中所述,集成项目中每个组件的版本都是显示指定并且唯一确定的,组件中指定依赖项的版本号在集成项目中并不起作用。
所以我们在组件发版时采用自动依赖组件池中最新版本的方式。这样设计的好处在于:
当基础组件库的接口和设计发生较大变化时,可以强有力的推动业务层组件做相应适配,保证了在高度解耦的项目架构下保持高度的敏捷性。但这种能力不能滥用,需要根据业务迭代周期合理安排,并做好提前通知动员工作。
研发流程琐碎的主要原因是研发需要人工参与持续集成中每一步过程,一旦我们把移动研发从持续集成过程中解放出来,自然就能提高研发生产力。我们通过项目集成发布流程自动化以及优化测试包分发来优化 MCI 流程。
研发流程中的组件发版、组件集成与 App 打包都是持续集成中的标准化流程,我们通过流程托管工具来完成这几个步骤的自动衔接,研发同学只需关注代码开发与 Bug 修复。
流程托管工具实现方案如下:
无论 iOS 还是 Android,在发布 App 包到市场前都需要做一系列处理,例如 iOS 需要导出 ipa 包进行备份,保存符号表来解析线上 Crash,以及上传 ipa 包到 iTC(iTunes Connect);而 Android 除了包备份,保存 Mapping 文件解析线上 Crash 外,还要发布 App 包到不同的渠道,整个打包发布流程更加复杂繁琐。
在没有 MCI 流程托管以前,每到 App 发布日,研发同学就如临大敌守在打包机器前,披荆斩棘,过五关斩六将,直到所有 App 包被 “ 运送 ” 到指定地点,搞得十分疲惫。
如同项目集成流程托管一样,我们把整个打包发布流程做了全流程托管,无人值守的自动打包发布方式解放了研发同学,研发同学再也不用每次都披星戴月,早出晚归,跪键盘了(捂脸)。
对于 QA 和研发而言,上面的场景是否似曾相识。
Bug 是 QA 与研发之间沟通的桥梁,但由于缺乏统一的包管理和分发,这种模糊的沟通导致难以快速定位和追溯发生问题的包。为了减少 QA 和研发之间的无效沟通以及优化包分发流程,我们亟需一个平台来统一管理分发公司内部的 App 包,于是 MCI App 应运而生。
MCI App 提供如下功能:
未来 MCI App 还会支持查询项目集成状态以及 App 发布提醒、问题反馈,整合移动研发全流程。
移动项目在构建过程中最为耗时的两个步骤分别为组件依赖计算和工程编译。
组件依赖计算是根据项目中指定的集成组件计算出所有相关的依赖项以及依赖版本,当项目中集成组件较多的时候,递归计算依赖项以及依赖版本是一件非常耗时的操作,特别是还要处理相关的依赖冲突。
工程编译时间是跟项目工程的代码量成正比的,集团业务在快速发展,代码量也在快速的膨胀。
为了提升项目构建速度,我们通过依赖扁平化的方法来彻底去掉组件依赖计算耗时,以及通过优化项目集成方式的手段来减少工程编译时间。
依赖扁平化的核心思想是事先把依赖项以及依赖版本号进行显示指定,这样通过固定依赖项以及依赖版本就彻底去掉了组件依赖计算的耗时,极大的提高了项目构建速度。与此同时,依赖扁平化还额外带来了下面的好处:
通常组件代码都是以源码方式集成到目标工程,这种集成方式的最大缺点是编译速度慢,对于上百万行代码的 App,如果采用源码集成的方式,工程编译时间将超过 40 分钟甚至更长,这个时间,显然会令人崩溃。
实际上组件代码还可以通过二进制的方式集成到目标工程:
相比源码方式集成,组件的二进制包都是预先编译好的,在集成过程中只需要进行链接无需编译,因此二进制集成的方式可以大幅提升项目编译速度。
为了进一步提高二进制集成效率,我们还做了几件小事:
尽管二进制集成的方式能减少工程编译时间,但二进制包还是得从远端下载到 CI 服务器上。我们修改了默认单线程下载的策略,通过多线程下载二进制包提升下载效率。
研发在 MCI 上触发不同的集成任务,这些集成任务间除了升级的组件,其它使用的组件二进制包大部分是相同的,因此我们在 CI 服务器上对组件二进制包进行缓存以便不同任务间进行共享,进一步提升项目构建速度。
我们在 MCI 中采用二进制集成并且经过一系列优化后,iOS 项目工程的编译时间比原来减少 60%,Android 项目也比原来减少接近 50%,极大地提升了项目构建效率。
除了完成日常需求开发,提高代码质量是每个研发的必修课。如果每一位移动研发在平时开发中能严格遵守移动编程规范与最佳实践,那很多线上问题完全可以提前避免。
事实上仅仅依靠研发自觉性,难以长期有效的执行,我们需要把这些移动编程规范和最佳实践切实落地成为静态检查强制执行,才能有效的将问题扼杀在摇篮之中。
静态检查最简单的方式是文本匹配,这种方式检查逻辑简单,但存在局限性。
比如编写的静态检查代码维护困难,再者文本匹配能力有限对一些复杂逻辑的处理无能为力。现有针对 Objective - C 和 Java 的静态分析工具也有不少,常见的有:OCLint、FindBugs、CheckStyle 等等,但这些工具定制门槛较高。为了降低静态检查接入成本,我们自主研发了一个适应 MCI 需求的静态分析框架 -- Hades。
Hades 的特点:
Hades 的核心思想是对源码生成的 AST(Abstract Syntax Tree)进行结构化数据的语义表达,在此基础上我们就可以建立一系列静态分析工具和服务。
作为一个静态分析框架,Hades 并不局限于 Lint 工具的制作,我们也希望通过这种结构化的语义表达来对代码有更深层次的理解。因此,我们可以借助文档型数据库(如:CouchDB、MongoDB 等)建立项目代码的语义模型数据库,这样我们能够通过 JS 的 Map-Reduce 建立视图从而快速检索我们需要查找的内容。
关于 Hades 的技术实现原理我们将在后续的技术 Blog 中进行详细阐述,敬请期待。
目前 MCI 已经上线了覆盖代码基本规范、非空特性、多线程最佳实践、资源合法性、启动流程管控、动态行为管控等 20 多项静态检查,这些静态检查切实有效地促进了App 代码质量的提高。
MCI 作为大众点评移动端持续集成的重要平台,稳定高效是要达成的第一目标,日志监控是推动 MCI 走向稳定高效的重要手段。我们对MCI全流程的日志进行落地,方便问题追溯与排查,以下是部分线上监控项。
通过监控分析 MCI 流程中每一步的执行时间,我们可以进行针对性的优化以提高集成速度。
我们会对异常流程进行监控并且通知流程发起者,同时我们会对失败次数较多的 Job 分析原因。一部分 CI 环境或者网络问题 MCI 可以自动解决,而其它由于代码错误引起的异常 MCI 会引导移动研发进行问题的排查与解决。
我们对包体总大小、可执行文件以及图片进行全方面的监控,包体变化的趋势一目了然,对于包体的异常变化我们可以第一时间感知。
除此之外,我们还对 MCI 集成成功率、二进制覆盖率等方面做了监控,做到对 MCI 全流程了然于胸,让 MCI 稳定高效的运行。
目前MCI平台已经接入公司多个移动项目,为了接入 MCI 的项目进行统一方便的信息管理,我们建设了 MCI 信息管理平台——摩卡(Mocha)。Mocha 平台的功能包含项目信息管理、配置静态检查项以及组件发版集成查询。
Mocha 平台负责注册接入MCI项目的基本信息,包含项目地址、项目负责人等,同时对各个项目的成员进行权限管理。
MCI 支持不同项目自定义不同的静态检查项,在 Mocha 平台上可以完成项目所需静态检查项的定制,同时支持静态检查白名单的配置审核。
Mocha 平台支持组件历史发版集成的记录查询,方便问题的排查与追溯。
作为移动集成项目的可视化配置系统,Mocha 平台是 MCI 的一个重要补充。它使得移动项目接入 MCI 变得简单快捷,未来 Mocha 平台还会加入更多的配置项。
本文从大众点评移动项目业务复杂度出发,详细介绍了构建稳定高效的移动持续集成系统的思路与最佳实践方案,解决项目依赖复杂所带来的问题,通过依赖扁平化以及二进制集成提升构建速度。在此基础上,通过自研的静态检查基础设施 Hades 降低静态检查准入的门槛,帮助提升 App 质量;最后 MCI 提供的全流程托管能力能显著提高移动研发生产力。
目前 MCI 为 iOS、Android 原生代码的项目集成已经提供了相当完善的支持。此外,MCI还支持 Picasso 项目的持续集成,Picasso 是大众点评自研的高性能跨平台动态化框架,专注于横跨iOS、Android、Web、小程序四端的动态化 UI 构建。
当然移动端原生项目的持续集成和动态化项目的持续集成有共通也有很多不同之处。
未来 MCI 将在移动工程化领域进一步探索,为移动端业务蓬勃发展保驾护航。
智聪,大众点评 iOS 技术专家,专注于移动工具链开发,对移动持续集成、静态分析平台建设有深刻理解和丰富的实践经验。
邢轶,大众点评 Android 技术专家,专注于移动持续集成、静态分析、静态化等 App 基础设施建设。
大众点评移动研发中心,Base 上海,为美团提供移动端底层基础设施服务,包含网络通信、移动监控、推送触达、动态化引擎、移动研发工具等。同时团队还承载流量分发、UGC、内容生态、个人中心等业务研发工作,长年虚位以待专注于移动端研发的各路英雄豪杰。
欢迎投递简历:dawei.xing#dianping.com。
本文首发于GitChat,未经授权不得转载,转载需与GitChat联系。
阅读全文: http://gitbook.cn/gitchat/activity/5b47267e01d81b73397ff138
您还可以下载 CSDN 旗下精品原创内容社区 GitChat App ,阅读更多 GitChat 专享技术内容哦。