不完美
人无完人,人写的程序自然免不了会产生各种各样的bug。
它就像空气一样,包围在我们周围,解bug可以说是每个程序员的家常便饭。
解bug的过程
一般可以分为3步:
- 复现问题。如果问题能稳定重现,比较好说。对于不好复现的问题,笔者一般做法是在可疑代码里添加一些辅助日志,然后将这些辅助日志上线,等问题下次再次出现时,就可以通过这些新增的日志推测原因。(如果日志太多,刷的太快,日志里面可以加上一些统一的关键字,这样可以通过grep查看自己关心的日志)
- 定位问题。定位bug问题过程中,会像侦探一样,仔细寻找各种蛛丝马迹。这个过程很关键,如果能很快的找到原因,那么解决问题就能得心应手了。
- 解决问题。方法多种多样,可以自己寻找方案,可以网上查阅,或者找他人讨论等。
一般到这里,就算是解决了这个问题。不妨在这个时候总结一下,在定位和解决这个问题的过程是如何的?笔者最近开始留意所经历大大小小的bug,从中总结了一些通用的解决模式,这样以后如果一条路走不通,可以换下思路,以便能够更快的定位和解决问题。
下面主要通过一些真实有趣的例子进行阐述,有些例子是开发过程中遇到的问题或者需求,不一定是bug,但笔者认为可以作为一种解bug的思路作为参考。
思路1-断点调试
以前端为例,可以在浏览器里设置断点调试,
node.js的项目可以在vscode里进行调试,
其他语言应该都有各自的调试方案。
断点调试或者添加辅助日志是最本能的一种方式了。
思路2-缩小范围
删除法缩小范围
好几次遇到css样式有问题,但是不知道到底是哪里的css产生的问题。
举个例子:
我们的页面使用了第三方ui库iview的table组件,这个组件给table自带了border样式,它的样子是这样的:


一开始的做法是每层元素找啊找,是哪个元素做了设置呢?由于border可能设置在很多元素上,比如div,table,thead,tbody,th,tr,td等等元素上,找了很久没找到设置的地方....
后来换了种方法找,在元素上右键"Delete Element",依次对可疑元素进行删除。如果哪个元素被删除之后,border没有了,那么就说明border设置肯定是在这个元素上设置的。 通过这样排查后,最后发现这个border被设置在了2个地方。
border-top和border-left设置在table最外层的div上;
border-bottom和border-right设置在table某个外层的before和after伪类上。
找到了这些border设置的地方,就很好对其进行样式覆盖啦。



二分查找缩小范围
如果某个问题是最近有次代码提交引入的,但不知是哪次提交引入。比如,团队有人说,"这个问题,之前都没有的,最近才出现...",可以考虑这个办法。
- 假设有问题的最新提交是commit1,
- 找到最近一次没有问题的提交点,假设为commit2,
- 那么导致问题的应该是commit1和commit2之间的某次提交,可以用二分查找办法,查找这2个点之间的有问题的提交。
- 最后根据查看这次提交的内容,推测问题原因
曾经尝试过一次,使用这个办法的前提是,需要确定哪次commit是正常的,这个是关键。
思路3-对比法
前端有个特点,同一个功能,经常可以有多种方式去实现,这个特点就为我们提供了一个很好解决问题的思路。
对比法是指,如果方法1有问题,那么使用方法2,如果方法2可以实现和方法1相同的功能,这样通过对比一下这2个方法的区别,从而找到方法1的问题所在。
举个例子:
前后端分离的项目,前端开发环境通常会通过webpack-dev-server,设置proxy和后端接口进行联通。
有次遇到个问题是,前端代码通过axios库发请求到proxy对应的后端接口,可是接口请求返回显示500,前端也没有报错信息。但是笔者通过postman直接调后端接口,返回正常的。
这说明接口是OK的,这就很诡异了,直接的办法当然找后端开发看下后台日志,查一下是什么导致的500,可当时后端开发不在,于是自己尝试换了js原生的fetch接口发请求,更诡异的是fetch发请求成功了!


思路4-搜索关键字
搜索工具是个我们的好伙伴,如何搜索却是一门学问。如果搜索关键字选的好,有些问题都能快速找到解决方案,也有些问题,需要反反复复修改关键字,才能找到解决方法。
我在使用hightcharts绘曲线图时,需要在series曲线点上hover时展示一个丰富数据的table和截图,如下图所示:

观察到的情况如下:
- 当选择时间区间较短时,小于8分钟左右,大概400多个点,能获取到point数据所有数据,包括x,y以及这个点上其他自定义的数据
- 当选择时间区间较长时,大于8分钟左右,能获取到point数据,但只能获取到x,y的值,无法获取到这个点上其他自定义的数据。
大于8分钟的效果如下:

于是开始搜索寻找问题所在和解决方案,尝试过以下各种关键字:
highcharts width limit tooltip formatter pointshighcharts 宽度 数据拿不到highcharts pointer undefinedhighcharts large data pointer undefinedhighcharts large number of points(data)
这些都没有办法,在这个过程中,又观察到1个现象,如果把highcharts容器宽度width设大一些,就可以获取大于8分钟时的hover数据,于是曾一度冒出偷懒的想法,希望能改下交互来解决这个问题,但是本着用户体验至上的想法,不能因为技术原因让用户妥协,还是继续查查吧。
皇天不负有心人,终于在官方issues里,通过下面这个搜索关键字下,总算找到了问题的答案!
highcharts points count less than data length
这个是highcharts官方issue里的一个问题 查看地址


根据highcharts开发人员的回答,Highstock(这是highcharts下的产品之一,笔者绘图也确实是使用的highstock,但如果用hightchats搜索应该更好)中有dataGrouping特性,默认是启用的,这个特性将指定数量的数据合并展现为一个点,显示的值根据不同的图表类型有所不同。所以可能是因为不同的点的数据被合并了,才导致hover时,展示的是undefined。
因此我们对应的解决方案就很简单了,直接禁止这个特性就可以了,设置dataGrouping.enable = false,即可关闭这个特性,只需要一个简单的配置即可解决啦

在找到答案之前,也考虑过其他解决方案,比如hover时想要的points数据不直接从曲线的points,而是将时间轴的x值作为key,其它需要的数据作为value存入1个变量,hover需要数据时根据拿到x值,从变量中获取。(由于后面找到最直接的方案,这个方案就未验证了)
在这个例子中,笔者获得几个想法:
- 去issues里搜索。这个适用于工程中使用了某些github上开源项目,如果遇到问题不好解决,优先考虑去github的issues里搜索答案,因为这里有来自开发者最直接的答案。这点在后好几次我使用其它开源工具时遇到问题时,都是通过搜索issues快速的成功解决了问题。
- 如何优化关键字,应该有很多方法。笔者未做深入研究,一点浅显理解是,英语要学好,多尝试修改问题描述,或者根据上次搜索结果,参考新的关键字,总能找到一些蛛丝马迹的。
思路5-查看源码
对于有些网上也不好搜到的问题,有的时候,顺着报错信息去查看源码,也不失为一种好的思路。
比如我在使用element-ui树组件时,使用了懒加载模式,其中有个问题就是,需要在最外层插入一个节点,天真的认为调用它的一些已有的insert/append类似API应该可以做到。比如在1个已有节点下加入了子节点,没啥毛病,然后期望用同样的想法实现最外层添加节点,尝试如下:



issues上有人提过这个问题,开发者的回答是无计划支持这个需求 地址
看着添加根节点时控制台的报错信息,要不就进去看看源码如何写的吧。于是找到报错入口,进入源码,大概研读源码,希望能找到一些希望。



从源码分析来看,报错的直接原因是root节点的data为undefined导致。为了验证这个,再次在断点调试时,查看了节点data,和判断一致。


查看root信息,发现root下有2个childnodes,但是data却为空

于是笔者想到的解决办法是给root节点添加一个data,然后将需要新增的节点调用insertBefore加入,这样接口就不会报data undefined的错误了。

解决了这个问题,API就能顺利的在树的最外层添加了新节点。

想必很多人也经历过这些,如果源码比较多,可以看下关键的地方,另外边调试边看,效率会更高。
总结
以上便是我总结的几个思路,相信在今后的工作中,可能还有更多的更广阔的思路。 笔者水平有限,欢迎多多交流和指正,谢谢。