2020 年 11 月 29 日,腾讯 2020「小程序·云开发」技术峰会在北京顺利召开。本次峰会以“重新定义开发”为主题,深度聚焦小程序云开发的创新成果与实践案例。以下为腾讯微信支付高级前端工程师张洪晖的演讲实录:
张洪晖:我是来自微信支付境外团队的张洪晖,我们在云开发 2018 年的时候就使用到了云开发这种方案,是第一批使用云开发的团队。用的比较深入,今天我给大家带来了我们在持续交付和质量管控这两个方面的经验。
首先前两个部分会给大家讲一下我们遇到了什么问题,我们为什么要使用持续交付。下面两个部分会讲一下质量的一些难题以及我们怎么去做质量管控的。
首先来看一下小程序的开发规模。这是微信提供的 2019 年的报告,小程序在当年带动了 536 万就业,对社会的贡献非常大。更恐怖的是它的同比增长达到了 195%,什么概念?这里做个小调查,在座的同学,哪一位投资收益年化能达到 195%的?请举手,这足以说明小程序这种指数型的增长,我们看到它的生态发展在未来是非常迅猛的。
讲了小程序,我们看一下我们做的是什么项目。
我们境外团队是境外游礼包项目,可以支持我们到全世界各地都可以获取我们的汇率优惠和优惠券以及礼包优惠。
回到开发这个主题,我们从传统的一个小程序开发模式,切换到云开发模式之后,我们的产出率增长了将近三倍。大家可能会有疑问,为什么我们的产出率切换到云开发模式后,会增长这么多?要回答这个问题,首先我们来看一下传统的开发模式是怎样的。
传统的开发模式,这是前端视角来看的,前端同学会负责小程序的 UI 以及逻辑构建,由后端时间实现 CGI 和后端服务,产品经理提需求,需要给前端同学提一遍需求,同时也要给后端同学提需求,这里就增加了沟通成本。需求定下来之后,前端和后端的同学其实是需要进行协议沟通的,这里我们也增加了我们协议沟通成本,另外由于后台服务往往会比较追求它的稳定,它的部署风险其实是比较高的,所以灰度流程会比较长。
因此在这种情况下,我们的开发效率受到这种限制也在一定的下降。切到云开发模式之后,我们看一下我们的流程变成什么样了。
后端同学只需要关注他后台的服务,而 CGI 这一层完全由云函数去进行承担,大部分场景下,我们的产品需求只需要前端一个同学就可以完成了。另外,由于前端同学做全栈的开发,也省去了我们协议沟通的成本。这对后端同学也是受益的,早上黄希彤老师说云开发使用之后,后端同学会颤抖,其实大家放心,后端的同学也是非常受益的。目前在这种模式下,后端同学可以更关注于服务的稳定性以及提供一些能力,让运营的玩法全部交给前端同学去做。
经过 2019 年的发展,我们项目参与人数越来越多。云函数也不断在增长,同时我们的用户增长也非常迅猛。但经过一年多的高速发展之后,我们也看到了一些问题。
第一,我们的发布没有审批。我们在开发者工具上右键点击上传,不知道是谁发布的,
这个时候另外也没有审批,万一发布错了之后,会怎么办。
第二,云函数是相互独立的。我们为了一些逻辑的互用,会提供一些公共的代码,这些公共的代码是由我们的脚本进行下发的方式,下发各个云函数。这给我们的代码提高了复用率,但是反过来提供的缺点,我们发的是残缺的代码。
第三,我们的云函数是在开发者工具里面点击右键上传这样的一种方式。这种方式,由于我们的云函数数量非常多,现在达到了 30 多个,一个个点击这种方式,在顺利的情况下,我们大概需要两个多小时进行部署和确认,在不顺利的情况下,可能一个上午的时间就过去了。
总结来看,我们的部署发布效率比较低,我怎么去提升?另外我们的流程比较多,注意点也非常多,我们怎么保证不出错呢?
这里我就引入了持续交互的概念,又好又快的用好我们的云开发。
首先给大家看一下我们持续交付流水线的总览。触发构建之后,我们是手动触发的方式,然后会有二级的审批,我们会去仓库里面拉主代码,拉完代码之后,我们会有代码一系列的检测和测试。测试通过之后,我们才会去走小程序和云函数两条发布的流水线,发完之后会去企业微信推送给大家,告诉大家进行了版本的发布。
下面详细来讲,这里可能大家会有一个疑问,我们为什么要用手动触发这种方式呢?它的效率是不是很低?确实除了手动触发这种方式,其实还有 git hooks 这种自动触发的方式,它的效率会相对来说比较高。
这里我们有我们的思考,其实自动触发这种方式比较适合的场景是我们测试环境,它对稳定性的要求并没有那么高,但是它需要即时去同步一些新的特性,在测试环境以及产品体验这个环节,我们用了自动触发的方式,但真正对外用户发布的时候,我们会用手动触发这种方式,并且会有二级审批的流程。
讲到触发,前面讲到我们一个一个点击云函数,其实部署的这种方式非常低,我们怎么去高效地部署云函数呢?我们会使用云开发团队提供的 CloudBase-manager-node 这样的基础库,在这个基础库之上,我们封装了获取云函数列表、部署单对云函数以及全量部署云函数的能力。
同时在小程序这一侧,我们知道今年年初的时候,小程序发布了 miniprogram-ci 这样一个自动化部署的能力,在这个能力之下,我们封装了自动上传代码包,免去了我们用开发者工具上传的这样一种方式。在发布之前,大家别忘了,我们也会提前去下发我们的公共代码,保证代码是完整的。
自动部署这种方式的效率非常高,用起来也非常爽,如果我们发布引入了一些 bug,会出现什么灾难性的结果?30 个云函数全部挂了,也会引入灰度发布的能力。
在初始化的时候,我们的小程序和云函数,会有小程序的新版本,云函数有两个环境:灰度环境和正式环境,现网的用户拿到了现网的小程序版本,我们可以放心的把我们一些新
的云函数特性部署到我们的灰度环境,并且提醒这个小程序版本,也会把路径指到灰度环境,当我们开始灰度的时候,慢慢扩大我们的灰度比例,把流量慢慢导入到我们灰度环境,同时现网的用户拿到旧版本的比例有一定程度的下降,我们要看一下我们的监控以及指标是否有问题,有问题的要进行快速的回退。
当我们灰度完成的时候,现网所有的用户拿到的都是正式版本的小程序,这个版本是 100%流量访问灰度环境。我们刚才所谓的灰度环境,这时候就变成了我们的正式环境;而我们的正式环境就变成了我们的灰度环境,这个时候就完成了蓝绿的一个切换,当我们下一次进行发布的时候,就可以把新的特性部署到我们的灰度环境。
这种设计有非常大的优势,大家可以思考一下。第一个点,它控制了我们变更的风险,可以及时快速的进行回退。第二是客户端和云函数一起进行灰度的,我们做一些破坏性变更,比如说协议变更的时候,完全不用管线上的小程序版本是否兼容新的协议。第三是基于灰度设计的能力,我们也可以做一些产品特性的快速验证。
有了整体灰度的能力之后,大家可能会问,我们是否有对云函数单独灰度的能力?我们也设计了这个云函数单独灰度的能力。我们可以看到,我们的小程序带着版本号过来访问,会请求到 getCloudEnv 这样的云函数,其实这个云函数没有做一些复杂的逻辑,只是单纯的去我们的云 DB 里面去获取当前这个版本应该访问到哪个环境,这里我们就会对灰度的比例以及白名单用户进行一个判断。
当我们带着我们的版本号返回到前端的时候,前端小程序就会根据这个版本号去访问到对应的灰度环境,我们也是基于此去设计了我们这个云函数的单独灰度。
这里给大家看一下效果。纵轴就是灰度比例,从 0 到 100%;横轴是时间线,可以看到红色这条曲线是我们的灰度比例,从 0 慢慢地放大到了 100%;而绿色这条曲线,当我们蓝绿发生切换的时候,流量从 100%慢慢下降到了 0。
除了灰度发布来控制我们的变更风险,还有很多质量检测的一些能力。比如说我们的 Lint 检查,防止我们的代码风格发生一些问题;还有自动化测试,来防止代码变更影响我们现网的功能;还有我们的一些代码报告,包括我们的安全漏洞、圈复杂度、逻辑死代码、风险 npm 包和代码重复率等这样的检测,所有的这些检查都是阻断式我们发布的,一旦发现问题,我们会阻止代码的变更。
看一下我们的效果,我们引入这条流水线和持续交互之后,我们统计了一下,变更了将近 150 余次,有效支撑了我们产品的迭代。
另外我们的部署时间从原来的两个小时缩短到了 5 分钟,这大大节省了我们研发的人力。
第三是我们引入流水线之后,其实我们是 0 故障的,让我们的发布也更有底。
下面给大家讲一下金融业务下的质量难题。当然这个议题跟我们云开发关系不是很大,但是大家各个团队都有遇到一些质量的问题。大家想一下,在没有质量的情况下追求效率是
否是真的在追求效率?
我们可以看一下做微信支付是一个传统金融跟互联网的结合,我们可以看一下传统金融有哪些特点。传统金融的稳定性要求比较高,一定程度上可以牺牲效率来换取我们的稳定。互联网追求的就是效率,当我们的质量和效率进行结合的时候,对我们的团队要求是非常高的。
给大家举个例子,这是我们小程序的发布节奏,平均每周一个版本,每天平均 800 行代码新增、300 行代码修改。业务压力来了之后,开发同学进行代码的变更,由于压力非常大,代码质量并不高,反过来会影响我们的效率,我们要及时进行重构和修修补补,需求堆过来的时候,又加大了我们整个业务的压力,这样我们就进入了负循环的、非常不好的循环当中。
我们怎么去破圈?业务压力大,我们想到第一时间先增加一些人力,当然我们的团队也在不断扩大,通过增加人力来减少我们的业务压力。我们有持续交付的流水线,重构抑制我们效率的下降。
反过来,人员增多也增大了我们管控的代码难度,因为每个人的代码质量都是不同的,另外代码风格也不同。另外我们重构一些代码也会影响线上业务的风险。我们提出了非常重要的一个点,我们的质量管控。我们通过质量管控抑制我们的质量下降,增加的人员会在一定的约束条件下进行开发,他提交的代码不合格,我们就不让他提交。在重构的这些代码当中,我们必须保证我们的自动化测试完全通过之后,才能进行代码的变更。
我们看一下我们怎么去省心省力的做好质量管控的。这是我们之前质量管控的一个现状,总体来说,分为需求、开发、发布和线上阶段。大概概括来说,可以分为事前事中事后的质量管控。
对于金融业务来说,这真的够了吗?我们做质量审计的时候,还发现了质量的问题,这里是小程序的底层架构图,相信对小程序开发熟悉的同学非常了解,我们的逻辑层和渲染层是分离的,我们的逻辑层无法拿到渲染层的结果。
假设在这种情况下,我们没有办法对渲染层进行监控,这时候我们的账单和资金展示出现了问题,怎么办?用户一定会投诉过来的,我们怎么防范这种情况的发生?我们首先想到做标准化的组件,最主要的就是金额渲染的组件,我们要考虑开发同学有没有更好的应用它或者有没有用对它,我们在开发流程当中,会对我们的敏感字段进行一些扫描,金额的一些扫描,看一下我们是否有正确的使用。
左边是一个例子,我们在提交的时候,我们发现这个关键字没有正确使用我们金额渲染的组件,就停止我们的提交。其实研发同学很聪明,他可以用一种方式去进行绕过,为了阻止这种情况的发生,我们也会在流水线中进行关键字的扫描。
静态金额渲染检查一定程度上解决了我们的问题,但是它足够安全了吗?当然不是的。大家想一下,如果我们的 money 拼错了,写成了 mnoey,是不是被漏过了?另外我们 UI 也有可能溢出,我们 100 元有一个视窗内如果只展示了 1 元,这个时候怎么办?也是一个账单
或者说资金展示的风险。
这里我们就引入了一个自动化截屏的方案,我们底层基于小程序开发者工具的 automator 的一个能力,有了这个能力之后,我们可以自动地拉起我们的开发者工具,并且跳转到对应的页面,然后去对数量进行拦截,提前写好我们接口的用力,拦截之后,由于我们的页面会比较长,会滚动地进行截屏,截下来的图片会进行图片的对比并进行归档,归档之后,还会去通知产品和研发去进行审核,再次发布。
这里为了给大家更直观的展示,我录了一个视频。我们用一个命令启动了开发者工具,大家可以看到开发者工具启动之后,会启动我们的模拟器,启动了这个模拟器之后,我们会根据我们预设好的一个路径去跳转对应的页面,由于页面比较长,这个时候我们会做一些滚动的截屏。当我们截完所有的页面之后,我们会在本地把这些图片保存下来,然后我们会对图片进行对比并且归档,放到一个网站上去进行对比。
左边是我们的旧截图,右边是我们的新截屏,两个截屏之间发生对比,中间是对比,发现下底部的优惠券这边,就是小红点发生了变化,我们就要关心我们本次变更是否有影响到这一块逻辑,如果没有的话,我们要及时排查问题。
这里就是刚才讲到的质量管控的总体思路,也分为事前、事中和事后几个角度去进行管控的。
最后给大家做一些总结和思考。
我们为什么使用云开发?云开发到底给了我们什么样的能力?
其实云开发给了前端同学一个全栈开发的能力,同时对后端同学也是非常受益的,后端可以更关注业务的稳定性。
第二,它其实是非常低成本的,这个低成本也包括我们的费用非常低,早上也有嘉宾分享 2000 多万只用了几百块的案例,另外低成本还包括非常低的开发门槛,让大家都可以进行手上。另外它也是零运维成本。
第三是我们非常看重云开发的生态能力,包括接入了微信支付、腾讯云的各种各样的一些套件,我们都可以使用,包括 CDB、COS 和 redis 等等,这些能力都可以接入进来。
最终的目标也是为了支持我们业务的快速迭代以及我们的小步快跑。用了云开发之后,大家也可以思考一下是否有用好我们的云开发呢?我今天分享的内容也是主要在效能,包括我们的持续构建、持续发布 ABTest 方面,在质量方面,我们也会有灰度发布、自动化测试以及 UI 的自动截屏,另外其实使用云开发也运用到了微信的私有链路,这时候也可以支持我们的安全防刷的能力。目标是一样的,最终是为了更好的支持我们业务的快速迭代以及小步快跑。
我今天的分享就到这里,希望能对大家有所启发,谢谢大家。
评论