本文整理自国内首届 Jenkins 用户大会演讲《让大象跳舞,手Q研发体系与工具实践》
讲师 | 潘金赤 编辑 | 白凡
讲师简介
潘金赤 腾讯高级工程师,毕业于华中科技大学,硕士学历。至今已在腾讯工作6年,任研发平台工具负责人。
腾讯内部大家更倾向于根据自己的业务特色做平台的封装,我想以“手Q”为案例看看腾讯内部是如何完成持续交付的。
今天的交流主要分为三大话题:
1、介绍手Q现状,以及存在着怎样的问题和压力
2、介绍内部各研发阶段的平台工具支撑体系
3、介绍手Q项目是如何将平台工具进行串联,达到怎样的持续交付效果
根据腾讯公司Q3刚刚发布的财报数据,“手Q”月活已经达到了6.5亿,同时在线达到了2.7亿,这里的同时在线包含PC和“手Q”,“手Q”已经占了非常大的比重,超过50%。
腾讯刚公布的Q3财报来看,手Q的月活达到了6.62亿,PC端手Q端同时在线超过2.68亿,在国内外的即时通讯领域,都是极有分量的一款产品。而在即时通讯以外,他还承载了非常多的社交及娱乐场景,公司内的各项产品也通过手Q平台提供功能和服务,从更便捷的触达到用户。
那到底是怎样的一个团队,打造出手Q这样子的服务亿万用户的产品呢?我们来看一张手Q项目团队的照片。其实是给大家开个玩笑,不过这张照片也确确实实反映出手Q团队的特点,一个是人多,而手Q的每一个版本就像一辆车,这么多人都在努力赶上这趟车。
“手Q”在版本发布上,面临这些挑战:
- 横跨公司7大事业群,20多个部门,研发测试超3000人
- 每个版本300 需求,10万 行代码,5000 测试用例
- 每个版本新建分支上百条
- 每月一个新版本
这里要介绍一下手Q的多版本并行模式,通常同一时间点会有3个版本会在进行中,每个版本交错叠加,一个版本的完整周期虽然需要3到4个月,但是相邻两个版本的发布间隔只有1到1.5个月,这样不仅可以持续刺激手Q年轻用户的新鲜感,也保证团队内各个角色成员在任何阶段也都能高效滚动起来。
刚才提到了拉分支,手Q的绝大部分需求都是在分支上开发完成的,每当一个新特性要启动,都会从主干上新拉出一条分支,在这个分支上进行需求开发。期间还需定期同步主干上的变动,而当功能开发完成后就会合回主干,并且将此分支冻结不再继续做其他功能开发。
系统测试通过后,版本准备发布时,会再拉一条发布分支出来,在发布分支上做最后发布前的确认。当然,如果此时如果还有bugfix同样也需要合并到发布分支去,直到最终发布结束。发布完成后发布分支也将冻结不再复用。这个就是手Q一贯的研发模式。
在分支开发的过程中,“手Q”这么大的规模,这么大的团队,遇到哪些问题呢?这个问题可能不仅仅是“手Q”团队会这样,我相信在公司或者项目的规模达到一定的层级之后,都可能遇到这样的问题。体现在研发阶段主要有这四类。
1、主干上面变动太大,几千人都在开发,提交时容易漏合、错合或者把别人的代码覆盖
2、测试的时候需要频繁的换包,经常测到一半,发现包更新了,需要重新换包来测
3、主干不稳定会导致主干编译失败,过多提交导致定位导致失败的提交记录困难
4、部署的阶段,涉及20多个部门,经常需要全部确认后才能部署,导致部署推进非常困难低效
为了优化上述问题,我们通过平台工具以及适度的流程建立,来将团队的研发效率提升起来。而在手Q团队内部,有着非常多的优秀平台和工具,来帮我们节省开发测试成本,并在一系列完善的流程指导下,规范并有序研发过程。下面我们将以研发阶段为划分,围绕几个有代表性的平台工具做一些详细介绍。
配置管理系统
这个系统是手Q项目一切自动化管理的源头,他记录了手Q的各个版本及分支信息,他主要包含以下三部分功能。
第一,分支管理,所有版本和分支不允许手动创建,而是来平台申请后自动创建,分支申请时关联好需求、敏感文件等信息,分支创建成功后不仅仅会自动创建好持续集成构建任务,同时也会持续监控分支需求状态,同步分支开发进度。
第二,代码管理,创建分支后,自动会自动每日定制帮开发完成主干最新版本的同步,分支负责人可自定义同步策略,代码出现冲突时也能预警并自动处理,同时系统会对分支定义的敏感文件进行保护,一旦敏感文件发生变动也会触发预警或拒绝提交。
第三,权限管理,开发必须通过配置管理系统来完成权限的申请,保证每次权限操作有据可查,这样可以很好的做到权限的隔离,保证权限最小化,而且一旦有团队人员发生变动,系统会自动完成权限清理,防止信息泄漏。
合流系统
合流的意思是把代码从分支上合到主干上,虽然说是非常简单的动作,但其实在实际的项目当中,会遇到非常多的问题。尤其是那么多人,大家都想在同一个时间点完成代码的提交,经常需要排队甚至睡在公司等待版本合流。针对这些乱象,我们搭建这套合流系统来解决出现的问题。
我们从这五个方面去完成合流的效率提升:
- 第一,建立流程。我们把合流分为三个阶段,满足一定条件以后才可以进行下一阶段的跳转,所有的流程都必须在线上做跟踪和追溯,同时保证每个环节的数据都是有据可查。
- 第二,分支管理,刚刚说了分支管理在配置管理系统已经落地了。我们清楚地看到每个分支计划和实际合入在什么阶段,保证我们所有的合流都是有序的。
- 第三块,双重验证,双重验证就是合流之前,要完成所有工具的测试。合入之后也要做准测试,保证合之前的质量是没有问题的,合的过程当中没有出其他的差错。
- 第四,权限控制,把所有主干权限收回来了,大家合入前测试通过后都会进入队列排队等待,轮到你的时候才能合。我们会有一个提醒,如果15分钟之内不来合流权限就收回了。权限给你的时候你还需要快速的合入,我们本来时间限定是1小时,超过1小时就有不断的提醒,告诉你主干时间太长了,出现了什么问题,要不要找人帮忙,或者让后面排队的人合。
- 第五,过程透明,过程透明的优势在于我不仅仅可以把我们的规则明晰出去,在明确规则的同时让大家相互监督。有了榜样的力量也能更好的让表现不好的团队能努力看齐。通过以上这些方法,让手Q合流不仅变得有序,而且合入质量都能有保障。而且因为有了各种测试工具的支持,以及规避中间环节出错的场景,使整个合流过程的效率也提升了许多。
代码扫描系统
代码扫描有非常多优秀的工具,包括PMD。我们内部的代码扫描工具将业界的优秀工具实践以及我们内部自研的工具进行结合,针对内部业务的特性做了适配和改造,在工具的基础上封装了两千多个规则级,这个规则级可以给各个业务不同场景做支撑的,各个业务也能单独定制自己所关注的规则集。
基于那么多工具、规则级的封装,我们能提供跨语言、跨平台的代码扫描或者代码静态检查的完整解决方案,并基于这些工具,支持到公司内部所有的平台、语言及业务。 主要功能包括:
- 代码静态扫描
- 代码分析、代码复杂度、逻辑复杂度的统计
- 功能测试过程中输出代码覆盖率信息,协助测试团队提供测试完成度数据
目前这个工具内部接入业务有60 ,每个月平均发现了接近3万个问题,这个问题我们内部统计了一下,包括代码规范,包括空指针包括内存泄漏,这些问题团队内部是最多的,也是需要团队共同解决优化的。
自动化系统
业界有许多自动化测试的工具,例如robot,QTP等,但是在实际使用中都经常会面临一些问题,针对手Q业务而言更加严重:
- 内部业务的改动多,尤其是界面交互的改动是非常频繁的
- 稳定性非常低,只要有任何一点界面改动之后,这些自动化用例都需要重新做调整。
- 我们的终端有很多自定义控件,如GF,挂件等,想通过外部的程序去做自定义控件识别也是非常困难的。
我们内部研发了这套自动化测试框架QTA,其实是整套完整的UI自动化的解决方案,涵盖了PC端、web端、安卓、IOS,也包括协议自动化,这个框架里面全部整合了。
- 完成了对各个端底层控件的识别和操作,这套框架也把这些控件封装成了对于内部业务来说比较好理解,也比较好做封装的对象。
- 测试基于这六项写自动化测试的用例,可以操作这些用例。
- 编写完用例之后,可以通过我们分布式测试的执行引擎。
- 跑完以后把数据结果汇总到报告平台,这个报告当中可以看到包括执行环境、测试版本,包括每个测试用例的情况,以及测试信息,包括不通过的时候会有截图,会有日志、堆栈信息都会展现。
这里有一份统计数据,QTA目前所有的用例有20000 ,测试计划2000多个,每个月执行测试任务7万多次。每个月跑的测试用例总数200多万份,这个量也是挺大的。
自动化测试必须要有设备,针对“手Q”,例如说“手Q”安卓来说,必须要有安卓的测试机。这么大的自动化测试量,我们测试机怎么办?
- 搭建一个机房,故障时跑到机房去查,形象难看
- 手机钉在离开发测试较近的墙上,方便查看定位问题
基于这个背景我们做了一个方案,就是安卓虚拟化,生产安卓虚拟机,所有测试在虚拟机上面完成,这样在测试开始的时候,我们可以根据测试的需要去虚拟化对应的操作系统、CPU和内存的需求。
在测试完成之后自动收回,这个跟早上说的构建跟docker的方案有点类似的,这个是针对终端的虚拟化。
这样的虚拟化之后我们还能够通过web方式,指定某台安卓虚拟机完成UI操作或者是命令行操作,或者是文件上传下载,我们可以直接通过本地,坐在电脑前,通过一个网页就可以看到某一台机器测试情况是什么样的。
与实体机相比,虚拟机有明显好处:
- 节省了设备采购和维护成本
- 实体机器跑的时间长了以后会劳损,电池会鼓胀,导致稳定性下降,而虚拟机不用担心测试稳定性问题
现在我们在“手Q”项目内部的,以及SNG内部多数的自动化测试都是通过虚拟机完成的
专项测试工具
专项测试,我认为这是“手Q”团队做的非常深入的一个领域了。专项测试涵盖资源类性能,交互类性能、稳定性、兼容性、安全方面的测试。
我们团队针对这里的每一块领域,都有一整套比较完整的解决方案,在版本上线前,甚至版本发布后都能够帮助业务团队定位以及分析各个环节当中出现的性能问题。这里也介绍团队中比较有代表性的两个工具。
1、New Monkey,这个是在Monkey工具的基础上研发,有更多符合我们的优势:
- 通过对控件赋权,保证各个UI控件都有同等概率被测试。
- 通过触发式自定义脚本,帮助进入复杂路径,保证更深层次的控件也能够操作到
- 他在记录crash堆栈的同时,能将crash问题聚类,避免同类问题反复告警;此外它还可以和其他专项工具结合,在稳定性测试的同时就可以采集上报其他性能指标
- 开发了随身版,大家不需要把这个测试固定到某一台机器上执行,每个开发同学自己带一台手机装个随身版,随时随地跑稳定性测试,这样大家发现问题的成本,或者说大家进行测试的成本就越来越低了
2、APM是属于一个资源类性能、交互类性能数据采集和分析的SDK。
- 各个业务接入这个SDK以后,可以很方便的完成比如说我在某个页面或者说某一个控件操作时的时延,或者说用户在使用某个功能的流畅度,以及丢帧的统计上报。
- 这个数据也是整合到“手Q”和SNG其他内部产品的线上版本。如果说当线上的版本有大量用户反馈说我们这个版本很卡,不好用的时候,可以通过后台开启开关,然后来记录用户在操作时候内部函数调用之间及渲染之间的时间差或者时延,或者内存以及CPU分配的情况。能够知道当前的卡顿到底产生在哪,协助开发更好的定位问题。
关于专项测试其实还有非常点可以深挖,这里介绍的几乎每一个专项范畴,我们的专项测试团队都有在外面的各个大会上做过分享,包括刚才我看到高效运维社区的视频广告,我就看到了一位来自我们团队的同学,经常在外面分享性能测试及优化之道。因此这里我就不深入介绍了。
为了表示对专项团队的敬佩和歉意,我帮他们打个广告,这本书是团项测试团队的呕心沥血之作,将他们在专项测试多年的经验及经典案例汇集的一本干货全集,是Android APP性能和开发工程师的必备案头手册。
众测平台
众测其实是一款基于众包概念的平台,内部业务通过众测这个平台投放测试任务,外部用户通过众测的网站或者APP上领取并执行指定任务,提交任务反馈。
我们会对用户执行任务的情况以及反馈问题的有效性进行校验,并将真实问题转化为产品的需求或bug进行进一步优化, 并对用户进行奖励。
通过这个众测可以达到几个目的。
- 第一,兼容性测试,因为我们内部做测试,包括之前也聊了一些测试团队,他们机型再怎么丰富,毕竟考虑到成本问题,比如说像我们之前用到大连兼容预测团队,机型就是200多,但外面用户机型是千差万别,通过众测的模式可以很好的实现兼容性的问题。
- 第二,功能用例覆盖,每个用例手工执行是非常耗时的,是否可以把没有发生太大改变的用例,或者基础的功能用例丢给外部跑,让他们帮我们保证这个功能没有问题,我们内部就可以根据其他的策略,比如说精准测试,或者freetest,来发现更多复杂交互问题。
- 第三,这里单独列一点,就是IOS灰度困难的问题,以前IOS要灰度就只能通过一个渠道,就是越狱用户,现在IOS用户越狱人数都越来越低,IOS用户都不愿意越狱,这样我们内部产品灰度的难度就越来越大。众测完成了跟苹果的对接,非越狱用户能直接完成体验版本的下载,保证我们IOS的灰度还能够按照复合苹果规定的方式进行,同时还能保证一定的用户量。
- 第四,现在AI比较火,大家都在搞AI。而AI一定需要大量的素材,这个素材的采集和标注,同样也可以通过众测,众测的价值就是人多力量大。
以上是我们众测平台以及APP的介绍。众测做了差不多接近两年的时间,目前帮我们内部投放了两千多次任务,平均每个月都有三十多个任务投放,已经累积帮我们发现了至少2000多个BUG。采集标注的素材也达到上万份。
CIS
来JUC不介绍持续集成好像不行,其实我觉得我们内部的持续集成做的挺一般的,因为得益于有了KK以及他的团队在Jenkins这块不懈的努力,我觉得任何团队都可以在Jenkins的基础上快速的搭建起一套自己的集成系统。我认为一套合格的持续集成系统,需要满足以下5点要求
- 第一,能自动或快速的配置及启动构建,例如定时触发或代码编译后触发。
- 第二,能很方便的提供编译产出的制品给到内部使用。
- 第三,上下游的串联。上游串联跟开发阶段结合,我当前构建是哪一个基线,这个基线完成了哪些功能的开发。下游就是跟后续的合流以及发布做一些结合,会拿构建结果作为下一步的数据输入。
- 第四,可以及时的把构建信息同步出来,失败了能立即有人关注到主干问题。因为以前构建老失败,我们这里放一个电视,看到红色的时候麻烦去解决。现在成功率比较高了,大家也不怎么用了。
- 第五,能对构建过程及效率进行统计,从而能分析出研发或构建当前的瓶颈点。只有做到以上5点,才能较好的让整个研发及构建环节顺畅的跑起来。另外,手Q项目中还做了非常多的编译优化工作,通过分包及增量编译的方式,将几百万代码量级的手Q构建的时长从此前的40多分钟缩短至最快10分钟完成,这里的故事我们先就不在这里深入介绍了。
晨报
我们希望每次构建就能够立即触发编译,立即触发自动化测试,但在“手Q”内部这样做不到:
- 一方面是因为代码确实代大了,编译慢,测试花的时间有点长
- 另一方面从成本上面考虑,我们不太需要让每一个代码提交都去编译或测试
为此我们只有适当拉长检查的间隔,只对对dailybuild进行检查,我们内部叫做晨报监控。晨报监控任务在刚拉分支时就可以默认创建好,同时可以灵活选择需要执行哪些工具测试,每天早上都会自动的拉取最新版本完成build和测试,测试通过后生成每日基线,编译或测试不通过时就需要相关负责人尽快解决问题。
此外每日监控的测试结果数据也可以复用于后续的其他测试场景,比如同个基线的安装包如果要发起合流,可直接拉取晨报监控时的测试结果,无需重复再执行测试。
以上介绍了我们内部用到的比较有特色的研发平台和工具,其实基本上我们内部用到的比较有特色的研发平台都已经做完介绍了,这里也想和我们DevOps里面有一点想做匹配,我们怎么样能够保证整个研发环节出现的瓶颈能够给到内部很好的正向反馈,能够持续的让内部项目持续优化,或者说把一些问题转化成新的需求,这些信息如何能有效的量化并很好的呈现出来呢?
过程度量和预警
过程度量和预警,就是将各个阶段、来自各个平台和工具的数据予以汇总,给到团队一个全景视图,例如从需求状态数据,我可以知道当前版本需求开发进度如何了。
从开发阶段,我能评估出当前代码变化趋势及提交频度。以及某些文件是否属于频繁操作文件,这个文件是不是该去解耦了。
测试阶段我们看到随着测试进行,我们BUG有没有收敛,这个版本有没有质量风险;编译阶段根据构建的时长的分布,我们要不要做构建编译的优化,或者说增加构建的集群。
发布阶段我能知道现在处于什么进度了;而版本发出去后,我可以很清晰的看到当前版本的crash数据是怎样。
除了单项数据的查看,各个业务还可以针对各个指标来配置阈值,当指标超过阈值后,说明项目存在风险,项目团队需要采取措施尽快规避风险。过程度量和预警这套服务监控着整个环节是否正常并实时反馈当前数据,一旦有特殊状况马上告警出来。
研发平台实践
在研发环境当中那么多流程,那么多平台,其实他们就有点像是一个流式的,在各个环节和下一个环节都是通过数据或者说一些过程阶段性的输出来保证我们各个环节的信息都是串联的。
在需求评审通过后,直接与开发的代码及测试的用例进行关联。而开发的代码必须由配置管理系统完成权限的控制,当开发完成分支上的开发,由合流系统来辅助完成代码的合并。合流及测试过程中都会需要调度各类自动化测试工具。
开发拉完分支,持续集成系统就会按照策略开始自动沟通,同时也会由晨报监控来把控构建产出的稳定性。团队成员可以很方便的获取到最新的安装包进行功能体验,当测试和体验完全通过后,经过发布管理的流程审核及操作,最终发布至外网。
此时外网启动相关监控,监控及用户反馈又将转化为新的需求,进入到下一轮版本迭代中。而在整个流程中都有数据度量及预警的监控和督促,让整个流程可以跑的更快一点。
这一整套平台工具为手Q项目带来了非常大的收益。
在开发阶段,因为不需要人工操作创建分支及权限开通授予,大大的降低了配置管理员的人工成本;因为分支和主干每日进行自动同步,保证主干和分支的差异最大不超过一天,分支主干差异变少了合入的冲突也会减少;
而在分支做代码合入时权限是独享时,能防止我刚同步完提交时又提示要更新,在开发阶段做的这么多工作,都是为了把质量风险前移,越早暴露问题,对项目的整体影响就越小;
而在测试阶段,我们通过各个工具明确了功能准入标准,当然自动化达标率也是标准之一,另外因为这些平台工具的支持,让测试效果和效率都能得到提升。
对于构建阶段最大的提升,不仅仅是在于成功率的提升,更多是在于明确主干问题的责任人,出问题了就能快速解决。而在发布阶段,保证整个发布环节严谨不出错漏,同时又能减少单点依赖提升效率。这一系列的改造优化,都不断的手Q的研发及持续交付流程越跑越快。
这里还想额外讲一下,因为之前我们提到,我们在做优化的时候,一定是平台加工具、加流程,刚才介绍的是平台和工具,我们是怎么在流程上完成优化的呢?这里我拿“手Q”合流这一点做一个流程介绍上面的分享。
刚才看到有合流系统,有自动化测试、代码扫描工具为这个合流过程做的加速。但在流程上,其实在合流这里体现的非常明显,刚才说合流分三个阶段,第一个阶段要完成这么多检查,但这个检查当中其实除了需求状态检查、分支同步检查、工具的检查以外,这些是必须要做的,就是所有在合流之前全部要做的。
但还有很多是流程上做考虑,比如说代码何如资格检查,什么是何如资格检查?每个新同学进入“手Q”项目,在允许参与“手Q”开发过程之前,他必须要经过培训、考试,而且考试必须达到一百分。
你必须得知道合代码怎么操作,遇到代码冲突怎么解,这些点必须考试通过才可以操作,否则可能会影响整个项目。
第二个是权限,此前说了权限完全由系统完成权限的和收回,而且必须要把整个项目的主干权限收回来。很多项目刚开始的时候就被这点难倒了,如果没有主干权限万一以后有什么紧急情况怎么办?最终流程带来的效果,让他们意识到这样做是有好处的。
第三点,合入后检查和权限释放更加是一个流程不断优化非常明显的体现。以前我们是必须合完代码,进行功能测试,测试通过后才能释放权限。后面我们做到由工具自动测试完成以后就可以释放权限。
再到后面我们可以确保自动化测试稳定性,确保代码开发合入过程中有一定的标准、规范的,因此现在是只要把代码合进去,包能够编出来就能够释放权限。这样流程不断的演变和优化从而达到最终效果。
这里也可以看一下这样规则带来效率的提升。我们现在“手Q”那么多的分支,平均合流的时间,这个是指从提交合流申请开始直到最终合流全部结束测试通过,最快一个半小时,最慢18个小时。
可能大家觉得这个数据不够直观化,我们拿一个对比数据。合流系统上线之前平均一个流合完要需要115个小时。系统上线初期,这个时间缩短到22个小时。
现在稳定了,大家比较认同,熟悉度比较高了,现在6个多小时完成合流了。而且这里强调一下,这个6个多小时并不代表整个过程都需要阻塞式的,真正需要排队的只有提交代码的那段时间,而这段时间我们也限定了不能超过1个小时。
我们也会对没有在1小时内完成代码提交的分支做一些分析和进一步优化,来继续缩短这个流程。所以从这里其实我们可以看到,虽然我们有着这么复杂的流程和规则,但是我们的效率还是挺高的。这里得益于之前平台和工具及规则的指定,关键点都在于提升自动化程度。
我们最后看一下“手Q”这套研发体系的效果,1.5小时能完成合入,3天内全部完成,80%以上的分支合入是准时的。版本发布的时候95%以上的Bug都能够解决,1月到1.5月发布一个版本,这样我们跑了34个版本了。
最后尝试做一下总结,我认为“手Q”在持续集成和持续交付这块,体现的几点特质,正好也是跟所谓敏捷开发及DevOps的基本理念,或者说几个比较重要的基本元素是符合的。
也就是流程、技术跟组织。制定明确清晰的准测,确保流程执行有效,最重要是确保的能到团队成员的认同和准时;在流程基础上,通过高度自动化来提升流程效率,并将流程串联起来保持数据通畅,降低人工值守场景避免出现单点。
而组织不仅仅在于人,更重要是在永远不满足现状的团队,我们通过过程分析了解当前项目进程,提前周知项目风险,并且不管反思研发环节中的问题,反推流程和工具的作出不断的改进。通过这三者的结合,让项目越转越快越转越顺畅。