写了个百万级的生产 bug !!!

2022-12-20 16:18:22 浏览数 (2)

Hi,大家好,我是晨光,好久好久不见呢。

最近这段时间躺地太平了,但是在雁卿同学的督促下,晨光觉得可以爬起来一下下。本次的分享,主要是想复盘下最近的一个生产 bug,主要内容分为如下几个部分:

  • Bug 产生的原因
  • Bug 修复的过程
  • 如何避免同类 Bug
一、Bug 产生的原因

Bug 的终极原因肯定是代码写出来的,但是为什么代码会有 bug,包括产品逻辑不通,自测场景不全以及开发失误等等,当然了,本次需求其实比较简单,所以这个 bug 是开发失误。

1、flutter 技术栈

问题现象: 在某种场景下,页面会出现灰屏。主要是 widget 侧的错误

问题根因: 空指针报错

报错分析: 这个空指针的字段 aBool 是在组件的构造函数定义时没有赋默认值,并且所有用到这个组件的地方都没有传 aBool 字段。也就是从头到尾,aBool 这个字段都会是 null ,但是使用 aBool 字段的地方写法是 !aBool, 那这时候就会报错。

因为 dart 是强类型语言,并不存在 js 中的类型转换这一说,所以在 flutter 中使用这样的写法时,一定要注意。当然了,这里最根本的问题是原始的代码规范不够好,导致后来想要优化代码时,就可能会存在这样类似的一些阻碍。

2、自测不到位

自测 case 缺失,所以这里的自测大部分情况只会回归测试大部分场景。类似这里发生的小概率的场景,就会默认也是成功的。但一般出问题的都是这种小概率事件。

后续这种自测需求,会尽量在开发前或者开发过程中补全自测case,等开发完成回归的时候,确保把所有逻辑都走到。

3、未及时找产品验收

没有及时找产品验收的原因是,测试环境一直有error,一进页面就有红屏 error,导致后来就一直搁置,后来服务发了生产,在定版前的一个小时,晨光找了产品去验收,但是大概率产品来不及验收。

对于这种情况,后续需要在开发过程中,就要追着产品让她验收,否则后续有问题的话,改动就不会那么及时了。

4、没有认真看代码逻辑

没有认真看逻辑是因为,使用的老字段一直存在,所以以为简单的复用不会有问题,但是稍微改了写法。这里的“稍微”就导致了这个空指针的报错。简单回顾下:

Bug 出现的大致原因如上图,改动也很简单,就是把第一点改成和第三点保持一致。this.aBool = false 给该可选参数设一个默认值

原始的代码中其实会有很多的 aBool != true,而这样写的原因大概就是因为空指针吧。

所以我们在写代码的时候,也可以对前人写的逻辑保持怀疑,因为他们写的也不一定全对。

添加新逻辑或者改动原有逻辑时,最好先确认下之前的逻辑是否存在漏洞和不规范的地方,如果实在拿不准,就和原有写法保持一致。虽然写起来恶心了一点,但大概率不会出错。

二、Bug 的修复过程

Bug 原因清楚了,就只需要修改代码了。

但是对于 app 来说,会存在版本的概念。比如 微信,也是会不断地升级版本。好多新功能,都在最新版上才会有。

新功能最优的情况就是没有bug,上线直接开流量验证需求价值,但保不准会出现一些没有覆盖到的场景等,所以就有了打补丁的方式修复这些 bug。

Bug 修复方式如下:

1、采用 hotfix 方式

打补丁,通过增量的方式下发修改后的代码,但是增量下载存在失败率,并且用户基数很大的话,失败的量也会很多。

比如我们的app有几百万用户,但是增量拉取失败的就有几万,那么对于这几万用户,命中了 bug 的实验的话,体验就会非常不好,而且万一用户投诉,也挺难搞。尝试了热修之后,效果不好,所以关了实验。

2、下个版本再上新功能

Bug 修复的代码在下个版本的分支上,下个版本的app,一定是不会报错的。

所以需要服务或者实验往后延一个版本再开实验,这样前端不会报错,但对产品来说,实验的用户基数可能会变小,实验数据不准确什么的,对产品同学的影响可能会比较大一点。

补充说明:什么是实验?

就有点类似于想做一个新功能,但是不知道效果会不会好,所以先做个开关,逐步灰度

有实验组和对照组,实验组是新版逻辑,对照组走原逻辑,假设实验组效果好,那么就会开全量,实验代码就会下线,所有逻辑走新版,老版本代码可去除。

如果没太明白的话,晨光举个例子:

比如你经常吃一个橙子味的糖,但是有一天你想尝试下荔枝味的,但是你又害怕荔枝味不好吃,原本准备买 10 颗橙子味的糖,最后买了 2 颗荔枝味的,和 8 颗橙子味的。

这里的荔枝味的就是实验组,橙子味的就是对照组。你没有全部购买荔枝味的糖这个操作,就是在做实验。

晨光有讲清楚吗,大家有么有理解实验这个概念咧,没讲清楚我们也进入下一个部分,感兴趣的同学可以私聊~

三、如何避免同类 Bug
1、自测

自测大部分是因为需求简单,或者测试小姐姐没有资源,又可能也没有自测 case,那么在开发过程中,代码逻辑包含的场景都需要尽量测试,mock可能只是看到样式生效,但实际的逻辑可能还是会有错误

所以经常会听到,测试小姐姐说,测试环境的什么bug还是没有修复,但开发会回复说 本地 mock 是好的呀。哈哈,懂的都懂~~

2、尽早让产品验收

对于这类自测需求,产品就相当于测试,但是对于不怎么负责的产品,可能就是大概瞄一眼,少数场景还是需要根据代码逻辑进行回归。

产品同学可能更多的是关注整个页面这种的。

3、看代码时更严谨些

上面也有提到,要对前人写的代码保持怀疑态度,有了这样严谨的态度,类似这种小问题,就不会发生啦。当然,最好不要犯低级错误,但是这次的 bug 是踩了前人留的坑了,防不胜防。

4、技术栈本身的缺陷

技术栈本身的缺陷是指,热修成本高,特别是这种一级页面,假设实验无法控制,要挂全部挂。甚至可能需要出一个新包来更正这个错误。那可能就是一级事故了。

当然了,flutter 还有一些别的缺点,空指针可能会导致整个页面挂掉。但是 RN 不会,最多就是某个模块出不来。但是 RN 的性能相比 flutter 会差一些,这应该也是前人选 flutter 的原因吧~

总结

啰啰嗦嗦说了这么多,主要是出生产 bug 的时候有点慌的,毕竟百万级别的用户,百分之一也有几万了,就算影响面小,还是会影响很多用户,所以要敬畏生产,特别是对于 C 端产品,本次复盘也是希望自己能够长长记性。

最后预祝大家工作愉快~生产无 Bug。

0 人点赞