有赞移动质量提升探索与实践
发布于 3 年前 作者 yjiang 3398 次浏览 来自 分享

有赞的移动端受到线下门店场景的特殊性影响,需要支持本地的离线计算和硬件能力更有限的收银机设备,这也对移动端质量体系建设提出了更高更严格的要求。我们在探索移动质量提升的过程中,沉淀出了一些思考与方法论。

质量与稳定性是技术团队的地基

在技术团队,质量的话题相信大家都不陌生。以有赞的业务为例,质量问题无论是发生在业务上的交易链路还是在引流链路上,亦或是启动时的闪退或 loading 时间过长的性能问题,都会造成我们所服务的商家经营上的低效和 GMV 的流失,导致商家对有赞的技术能力产生质疑和抱怨,最终影响到有赞SaaS服务的续费率。

但事实上,质量不佳不仅会影响到业务和商家,对于技术团队自身的影响也不容小觑。

有赞移动团队也曾经历过从0到1快速迭代功能上线而对代码质量重视不足的阶段,这些挖下的坑在业务快速拓展的过程中带来了大量的线上问题和故障。线上问题的频发会让整个团队陷入一种效率上的恶性循环:应对线上问题会打断进行中的项目进度,严重的时候很多开发同学甚至不得不整个白天都在忙于处理线上问题,到了晚上才有空开始补今天的开发进度。这种情况下不仅会产生加班、延期等显性的影响,更严重的是技术方案考虑不周、Code Review不细致等隐性影响,会进一步降低线上代码的质量。这样的恶性循环也会让整个团队忙于救火,技术沉淀和氛围更加无从谈起。

▲质量不佳对于技术团队会形成恶性循环

因此我们深刻的感受到,对于一个技术团队而言,质量和稳定性其实是团队的地基。在好的质量基础上,我们才能更好去追求业务上的支撑与推动、研发效能提升、团队技术氛围等其他目标。

有赞移动质量要求的特点

不同类型的业务场景中,对于移动端的要求也会有不同的侧重点。有些金融背景的业务会对于 app 的安全性要求更高,而另一些电商背景的业务可能对于动态能力要求更高,而技术团队在质量上努力的方向和侧重点都与业务特点密切相关。

那么有赞的业务场景中对移动端有哪些要求呢?我们归纳成以下两个突出的特点:

  • 离线的业务能力
  • 受限的硬件水平。

1、离线的业务能力

对于市面上的大部分app,当用户在移动 app 上操作下单的过程中,移动端通常只会负责信息的展示和用户的交互。而订单金额的营销计算(比如某个商品是否可以用优惠券减钱、某个商品是否在订单中符合成为赠品的条件)、数据的校验、订单的生成这些敏感的业务逻辑都会放在后端进行处理。

但是在有赞的门店业务场景中,我们为门店收银员开发的收银终端 HD 应用需要提供离线开单的能力。

这是因为门店场景中面对的是来店的顾客和真实排在收银台前的待付款消费者。这种场景要求收银系统在面临断网或者服务端宕机的挑战时,需要具有本地收银的能力。如果来店的消费者因为收银系统卡住而离店,那么商家就会蒙受巨大的损失。

▲门店场景中供门店收银的HD应用

本地去做营销计算和订单生成的要求不仅对于移动端本地数据缓存能力、数据变更及时性、逻辑复杂度、数据安全性提出了更高要求,在质量保障上还带来了两点挑战:

  • 营销计算中的资损风险
  • 问题的及时修复能力

营销计算中的资损风险:如果移动端在创建订单过程中只负责信息展示和用户点击操作时,移动端由于自身 bug 导致资损风险的概率是极低的。但是当商品的折扣计算、优惠分摊、组包拆包、优惠叠加互斥逻辑都落在移动端本地时,编码 bug 导致订单金额计算错误,进而导致商家或者消费者资损的概率就会直线上升。比如一个商品并不在商家的限时折扣活动范围中,但是由于bug导致给这个商品也打了折扣卖了出去,就会给商家带来资损。而资损故障是非常严重的。这就要求我们必须有更严格的机制去确保核心代码的L0级稳定性。

问题的及时修复能力:当线上问题可能涉及资损时,也进而会对移动端的问题修复能力提出更高的要求。

就问题修复及时性而言,移动端相对于前后端有着天然的劣势。后端或者前端同学发现线上问题时,可以通过回滚做到几分钟内止血。但移动端不可能让每个终端卸载重装老版本,同时市面上的热修手段也存在诸多限制。这让我们不得不对于问题修复流程中的每个环节做更深入的思考与探索,尽可能在问题发生时能够快速止血,降低影响面。

2、受限的硬件水平

在门店场景中,我们为门店收银员提供的HD应用安卓端是运行在收银机上的。对于收银机的硬件能力,我们可以通过一个简单的对比感受一下:

  • 商米 T2 收银机,也是我们目前客户中使用率较高的一款设备,内存2G,某电商平台上售价3000多元
  • 红米 Note9 手机,安卓千元机,内存6G,某电商平台售价999

我们抛去 CPU 能力等其他因素,但看内存这一项就存在着巨大的差距。有限的内存能力,要求我们移动技术同学不仅在编码和技术方案设计阶段在性能上有更细致的考量和设计,也要求我们对于线上的 app 性能卡顿问题有更强的分析能力和解决能力。

有赞移动质量提升的探索与实践

结合前文提到的有赞业务场景的要求,我们着重围绕以下几个命题,思考和探索如何提升移动质量:

  • 如何深度防范资损故障,让资损的风险尽可能清零?
  • 如何体系性的提升移动端质量,让线上问题数量保持在较低的水平?
  • 如何搭建完善的性能监控体系,全面提升app性能,降低卡顿的发生?

我们将探索中的心得归纳为以下几点:

  • 主动发现问题
  • 更早发现问题
  • 有效的流程机制支撑
  • 重视性能

1、主动发现问题

在我们曾经出现过的一例线上资损故障中,由于场景实际触发频率较低,导致测试过程中被遗漏了。这个bug是6月6日发布上线的,但是直到7月10日有一个商家上报了一例我们才发现了这个涉及资损的问题。这件事情引发了我们的反思,对于核心业务链路上的异常行为,难道我们发现问题的途径只能依赖用户上报吗?

天网数据报警平台

事实上,主动去发现和修复问题对于移动端同学并不陌生。一个移动团队即使是在建立初期也会通过一些三方平台,对自己每个上线的版本进行 crash 的监控和分析。crash 平台就是主动发现和解决问题的表现。那么业务流程中的问题,我们是否也能做到主动上报、主动发现、主动修复处理呢?答案一定是可以的。

因此我们搭建了天网报警平台,目标就是对于核心业务链路上的异常情况,可以达到 crash 上报、分析、跟踪的同样效果。一套 crash 分析平台通常具备以下能力:问题上报、数据聚合、任务分配、版本过滤、上下文信息等,我们的天网平台也提供了相同的完整能力:

  • 数据上报:通过业务核心环节的主动埋点,对异常进行主动上报,根据问题不同分级支持设置不同的上报优先级策略
  • 数据聚合:相同的问题通过后台进行聚合,提供问题列表并支持各种条件筛选
  • 任务分配:问题可以分配给责任人跟进
  • 消息报警:当问题符合报警策略,自动关联到企微报警,并直接at对应业务域的负责人,第一时间介入处理
  • 版本过滤:问题修复后支持设置已修复版本,后续上报问题如果小于等于已修复版本则不再报警,如果大于已修复版本则代表问题再次发生,会再次报警需要跟进
  • 周报日报:周期性汇总线上报警问题数量和状态,提醒责任人及时处理

搭建了完整的平台能力之后,我们也深知整套系统的有效运转其实是深度依赖于业务同学在业务流程的关键环节中的主动分析和埋点,丰富的业务埋点才能让这套系统真正在业务主动防控中发挥效果,因此我们还汇总了适合业务主动埋点的最佳实践:

  • 数据校验:对于端上通过输入或者计算产生的数据,可以通过交叉校验分析异常;
  • 关键内容缺失:各环节在收口阶段均可以校验自己获取的参数完整性,如果有关键内容缺失可以主动上报;
  • 系统异常:无论是 iOS 系统 API 返回了 error,还是 Android 系统中 try/catch 的异常,都代表本地系统调用出现了预期外的行为,可以主动上报

以下是一个天网报警的例子,在收银员操作一笔订单的过程中,移动端上报后端的开单参数中会包含以下信息:

  • 商品信息(如一听可乐,售价3元)
  • 营销信息(限时折扣7折,或者会员价2.5元)
  • 支付信息(最终通过会员价2.5元结算,通过现金进行支付)
  • 会员信息(用户登录的会员、在该笔订单中所使用的是哪张会员卡等)

我们曾经出现过的一个bug是在大型项目改造的过程中,在调用后端API传参时没有传选中的会员卡号。这个场景下,当这张会员卡有发放多倍积分的设置时,就会导致该笔订单最终发放的积分错误。这种场景下,我们增加对参数的主动校验:当开单参数中的营销信息中存在会员卡优惠,但是会员信息中又没有传卡信息时,就很有可能是开发中出现了bug,通过这样的参数内部交叉校验,我们就可以进行主动上报。

事实上,在一年后的一次重构过程中,开发同学真的又一次出现了同样的失误,而天网报警提供的信息这次就给与了我们很大的帮助。

截止目前,我们已经在业务核心链路上预埋了上百个报警点,并在线上多次真实预警了线上问题,让我们可以第一时间进行主动修复。

2、更早发现问题

看完前文可能有细心的同学已经会问了:如果对问题进行了埋点报警,那么又何必等到它上线再去处理呢?是不是在上线前就可以把问题修复掉?

回归阶段

答案当然是可以的。有赞的移动端发版是采用发版车机制,每周一我们会将测试验收通过的需求代码 merge 到 dev分支,去打出“高铁包”给测试同学进行回归,并且配合自动化测试进行核心流程的回归验收,下周一高铁包将会发布到市场。而高铁的这一周时间,就是回归发现问题的最佳时机。

因此我们将 crash 分析报警和天网业务告警的范畴都拓展到了回归阶段。高铁阶段的问题同样会主动触发报警,过去一年间,这两个平台都有多次在 bug 上线前主动报警的立功表现。

开发阶段

回归阶段报警并不是我们思考的终点,核心链路问题的发现和解决还可以更早吗?在开发阶段,甚至是方案设计阶段,有机会提前把一些线上问题扼杀在萌芽中吗?

我们在针对端上可能发生资损的环节设计了单元测试,并将单测的运行接入到了 CI 流程中,这样代码在提交时,就会直接经过单测的检验。

那么什么样的代码适合写单元测试呢?

我们经过讨论,将范围圈定在了移动端重新建模和发生运算两种场景上,各个业务域的同学通过梳理产出自己的单测用例。

方案设计阶段

还有比开发阶段更早的时机吗?可以在项目开发前就主动预防吗?我们在移动端设计了行为校验机制

行为校验

所谓行为校验,就是将用户的操作行为和数据进行交叉校验,这个校验可以增加一个新的维度来预防 bug 的发生。

我们仍然采用上文提到的订单参数中忘记传会员卡信息的 bug 为例,这里选中卡这个操作是客户端用户点击触发的,那么用户选卡的这个操作就是最终开单参数中应当包含会员卡的交叉校验点。

这样的校验逻辑对于我们就是一条“校验规则”,我们开发了行为校验的底层SDK,就是在核心开单业务链路上通过将全流程的用户操作行为和最终订单数据进行double check,新增一个维度来为业务保驾护航,提前避免开发过程中的低级失误引入 bug 的可能性。

类似的规则例子还有很多,比如一笔在线订单收款成功之前,一定曾经成功调用过支付接口,可以用来预防一些同学在页面跳转上的bug;

目前我们的行为校验已承载了核心业务链路上的多条规则,大大降低了资损故障的可能性。

▲问题的发现和解决贯穿整个研发流程

3、有效的流程机制支撑

虽然我们有了多样的工具平台来报警和及时发现问题,但是这样就可以提升质量了吗?在实践中,我们深刻的认识到,工具只有在配套高效合理的流程机制支撑,才能真正发挥威力。

在平台搭建初期,线上的crash和数据校验报警平台在报警时缺乏策略,没有就报警频率和at的负责人做收敛,导致单台设备的一个小问题,机器人就会短时间在群里发出几百条at所有人的报警消息。这种“狼来了”的报警只会让大家关掉群消息提示,或者关掉企微的通知。

不懂得克制的报警,相当于没有报警。

因此我们反复优化了报警策略,以“报出来的问题都是需要立即响应,不需要立即响应的都不要报出来”为原则,沉淀了一系列报警策略,详细内容可以参见之前的文章《有赞移动天网平台搭建》中的相关章节。

除去报警策略,我们另一个在流程规范上的沉淀是在Code Review环节上。

betterMR

在我们团队质量问题最严峻的时期,我们扭转被动战局的核心手段还是加强Code Review。但CR这件事情要想真的扎实做出效果,而不流于形式,是非常依赖好的流程机制进行支撑的。在强化和落地CR的过程中,我们面临以下挑战:

  • 效率问题:我们约定每个MR都需要2个reviewer去做CR。事实上在整个CR过程中是需要很多沟通成本的,开发同学将MR发给两位reviewer,reviewer会提一些建议反馈,开发同学进行修改后再次review,这个过程可能会反复多次,直到两位reviewer都同意merge最后合并,整个过程中需要大量的沟通。而且reviewer常常手头也在忙要晚些才有空,就更加会拖慢开发者的节奏。

CR过程中的沟通成本

  • 颗粒度问题:一个项目中,改动到几十个文件数千行代码并不是小概率事件。reviewer要想在这么大面积的代码中找出一些细节的逻辑问题或者typo的低级问题并非易事。
  • 时机问题:以往我们CR的时机是放在上线前,事实上这个时间提出的一些优化建议已然太晚,如果想要优化改造又需要测试再次介入。因此一些好的建议只能尘封积灰,有些可能很久都等不到下次优化的机会。

我们意识到,CR的过程必须通过流程规范提高其效率,降低对开发同学的打扰和负担,这样大家才能真正高质量的投入到CR中,相互保驾护航。

最终我们推出了betterMR机制,通过以下机制解决以上的挑战:

  • 硬性要求:所有上线代码,至少2人review通过后才可以合入dev
  • 时机问题&颗粒度问题:代码在开发过程中,拆分成多个子任务,分批提MR合并到自己的feature分支。因此CR过程可以穿插到整个开发流程中,而不是在上线前最后review
  • 沟通成本问题:企微通知全程介入CR流程,核心链路通知相关人,无需线下单独沟通
  1. CR发起:开发同学在MR中at两位reviewer,两位reviewer都会收到企微通知消息
  2. CR建议:reviewer提出建议后,在评论中输入[N]命令触发企微通知给开发同学
  3. CR再次review:开发同学根据建议完成改造后,在评论中输入[R]命令触发企微通知给reviewer再次review代码,确认建议已落地
  4. CR通过:reviewer通过后评论“+1”,当MR中已累计两个“+1”时,开发同学会收到企微通知,代码已可以合并
  • 及时性问题:团队对MR进行了分级,对应提出了及时性的要求
  1. 普通MR,要求24小时内完成review建议
  2. 紧急MR,要求2小时内完成review建议
  • 数据汇总激励:我们针对MR还统计了周报和月报,对于团队中积极review代码的同学,在周会和月会上给与激励,让大家都认可review的积极效果

这套机制我们在2020年6月推出后,团队的线上问题数量立刻得到了有效控制。我们在当年Q3迅速将线上问题数量缩减到了之前的1/3,并在之后长期保持了很低的线上问题率。

▲过去两年移动团队的线上问题走势

▲配合有效的流程机制,工具能力才能真正发挥效果

4、重视性能

前文也提到有赞移动的性能挑战。在性能问题上我们的动作包括以下三个方面:

  • APM平台的搭建:主动发现线上问题,并且为线上卡顿问题提供分析数据与线索。APM平台的详细设计与实现,参加之前的公众号文章《有赞移动性能监控平台(二)》
  • 线下监控平台:对于性能问题,我们也同样在探索在问题上线前发现和解决的可能性。我们所搭建的线下监控平台,在回归阶段对关键环节进行自动化测试并采集数据,如果发现同比上个版本某个数据有显著提升,就会报警提示开发接入排查;线下监控平台的详细实现参加之前的公众号文章《有赞移动性能监控平台(一)》
  • 主动优化:根据APM平台和线下监控平台的数据与反馈,我们会主动安排性能优化的方案,对app性能进行持续优化。我们之前的公众号文章《线程池优化与监控》就是其中的一个典型例子。

▲可用性、性能与流程规范共同构建了移动质量建设矩阵

质量提升的成果

过去两年我们在质量上的深耕与探索也给我们带来了丰厚的成果,这个成果不仅体现在我们的月均线上问题数量上,更体现在我们持续的技术产出上。技术同学救火的频率低了,就有更多时间主动出击,去体系化的搭建系统去预防线上问题的发生,预防机制又能进一步降低线上问题发生的概率,形成良性循环,这无论对于团队,还是开发同学个人的成长都是很有帮助的。

最后

本文讲到的有赞移动质量提升与实践的过程,其实也一定程度上代表了我们团队的工作方式。我们在应对有赞业务场景的过程中,会遇到如离线收银、性能深度优化等有挑战有意思的技术难题。而面对这些挑战和难题,我们会主动出击,寻求体系化的解决方法。这些解决方案中往往还会涉及到后端服务和前端页面的工作,以及产品化的思考,我们移动同学在此过程中不设边界的拓展自己的技能包,最终形成让人颇具成就感的技术沉淀。

回到顶部