我的代码真的没有bug,稍等,先试试小黄鸭调试法
今天测试同学为了赶进度,加班去测试我的功能。
因为我的代码都写完了,也没有陪测的必要,所以就没去了~
下午第一个问题提过来,根据经验,这个应该是测试的逻辑问题,最后他自己也发现了。
过了一会,提了第二个问题,说是本该命中条件进入某个等级的,没有进入,跳到下个等级了。
拥有几年开发经验的我,此时当然不会说“我的代码没有bug,你再试一遍”。说出这句话的成本近乎为0,但是脸要是打起来,那是真的疼啊~~~
脑海中快速思考下,发现不是靠脑海中演练就能给出答案的,于是乖乖的,掀开电脑盖,指纹解锁,连接VPN,查看日志,一气呵成。
因为这个需求指标巨多,流程相对较长,所以我已经在代码的关键节点打印了数据日志。
所以,想要的信息,日志都是有的。只是,仔细看了下日志的数据,又认真的比对了测试同学给出的测试数据。讲道理,这确实应该命中。
可是事实就是没有命中,于是开始排查。
查看配置中心
因为指标多,每个指标都有阈值,首先第一反应当时是别人的锅,所以我不放心的看了看是不是测试同学调整的参数阈值有问题,看完后,我有点愧疚,这不是测试同学的问题,指标都对上了。
但是还是不死心,是不是没有按照我给他说的要点选热加载选项,导致指标没生效。想到这里,我有点小激动,没错,我又可以表面轻描淡写,实则内心激动的告诉他真相:你这个是配置忘记勾选了吧(怎么回事,又是你的问题)
想归想,想要趾高气昂就要有底气,要底气就得拿证据。
我们的配置中心做的就是这么贴心,每一次操作都可以查看历史记录。赶紧点一下,然后截个图,甩给他。
等等,这个,没想到啊,测试同学居然这么严谨,选项勾选了。
emmm
调整策略
从日志来看,测试的数据没有问题。
从配置中心来看,配置也勾上了。
测试排除嫌疑,真相只有一个,是我的问题(自己打自己脸,下手可以轻点)。
虽然家里连上了VPN,也可以看日志、发布项目,但是本地启动服务不好使,UT也跑不通。
那只能看代码了,要知道,近朱者赤近墨者黑,找别人缺点,那是章口就莱,一莱一个准。
找自己的问题?首先得否定自己,知道自己原来也是有瑕疵的,这是多么难的事儿,但是我做到了!
为了给测试同学一个交代,我开始老老实实的研读自己的代码,企图一眼就发现自己的不足~(太南了
失策了
涉及测试点的代码逻辑也不复杂。大概过程是这样的
上游并发调用获取各个指标的当前值 -> 在规则层过滤 -> 如果命中两个规则条件则视为命中,否则未命中
于是,按照测试同学提供的两个指标以及提供的测试数据比对两个规则的阈值。
从日志来看,上游的数据是没有问题的,从数据比对来说,应该是比对通过了,但是没有命中。
于是开始仔细检查这两个规则相关的代码,以防出现,手抖把"!="写成"=="的情况。
很遗憾,在我认为比较关键的地方查看后,发现我的代码就是这么严谨,找不出任何破绽。
为了不让测试同学hang在我这个线程上划水、摸鱼,我得先释放锁:“代码看着没啥问题,你先测试其他逻辑,我再看看。”
小黄鸭救了我
我心里清楚,虽然我有一点散光,但是眼睛还没瞎。
所以即使再比对十遍八遍,肯定也还是找不到bug。
是时候换一种思路了。
上面说了,上游代码排除嫌疑,涉事代码本身排除嫌疑,当然,测试同学也排除嫌疑,更别说下游代码,下游完全不知情啊。
仔细想想,两个规则之前还有有其他代码的,虽然也是一个规则。我决定擦亮双眼,人肉找bug。
把自己当做一台没有感情的机器,一遍读这我写的工整简洁的代码,一遍计算代码的结果,再到排除嫌疑。
上游赋值没有问题!
变量初始化和结果返回没有问题!
第一个规则没有问题!
第一个规则没有问题!
其他初始变量赋值和返回没有问题!
然后开始过第一个规则和第二个规则之间的中间规则代码。
在方法返回的时候好像没有返回期望的值啊?!
没错,我把本来应该不管命中与否都要返回的一个变量值,只在命中的条件里赋值返回了。如果没有命中这个规则,则没有赋值,那实际上返回的是这个变量的类型默认值,也就是0,归零了!
趾高气昂只会迟到,但永远都不会缺席。
我告知测试同学,我应该知道原因了,我修复下,一会再试下,后面的“英雄事迹”就不多介绍了。
总结盘点
虽然不是什么大问题,也不是什么线上大事故。
只是想表达,几乎没有人敢说自己写的代码0bug,写完就可以上线。曾经有跟我这么承诺和标榜的人,最终都是难逃翻车和打脸的命运。
有问题,理性分析最重要,从涉及bug的方方面面,包括经手的人和代码本身,都有可能出问题。
有时候,如果发现是自己的问题,但是又迟迟找不到原因,不要一个人闷着头苦苦思索,找个同事来帮你一起找。有时候就在你准备让别人一起来看看,你开始描述问题的诡异之处,还没说完,你就突然知道了原因。不知道你遇到过没有,反正我有。
今天回过头想想,哪些被我叫来的人其实就是工具人,他们和小黄鸭无异。
什么是小黄鸭和小黄鸭调试法呢,参见百度词条
此概念是参照于一个来自《程序员修炼之道》书中的一个故事。传说中程序大师随身携带一只小黄鸭,在调试代码的时候会在桌上放上这只小黄鸭,然后详细地向鸭子解释每行代码 。
许多程序员都有过向别人(甚至可能向完全不会编程的人)提问及解释编程问题,就在解释的过程中击中了问题的解决方案。一边阐述代码的意图一边观察它实际上的意图并做调试,这两者之间的任何不协调会变得很明显,并且更容易发现自己的错误。如果没有玩具小鸭子也可以考虑向其它东西倾诉,比如桌上的花花草草,键盘鼠标。
类似这样
或者这样
找不到鸭子,找同事也一样~
如果您觉得阅读本文对您有帮助,请点一下“推荐”按钮,您的“推荐”将是我最大的写作动力!如果您想持续关注我的文章,请扫描二维码,关注JackieZheng的微信公众号,我会将我的文章推送给您,并和您一起分享我日常阅读过的优质文章。
我的代码真的没有bug,稍等,先试试小黄鸭调试法的更多相关文章
- 转:Eric Lippert:阅读代码真的很难
转自:http://blog.jobbole.com/438/ 相关文章 微软资深软件工程师:阅读代码真的很难(第2篇) 阅读优秀代码是提高开发人员修为的一种捷径 学会阅读源代码 如何阅读大型代码库? ...
- 来试试这个来自静态代码分析工具PVS Studio提供C++的小测验吧
博客搬到了fresky.github.io - Dawei XU,请各位看官挪步.最新的一篇是:来试试这个来自静态代码分析工具PVS Studio提供C++的小测验吧.
- [置顶]
几行代码实现ofo首页小黄人眼睛加速感应转动
最新版的ofo 小黄车的首页小黄人眼睛随重力而转动,感觉有点炫酷,学习一下吧,以下代码是在xamarin android下实现 ofo首页效果图: xamarin android实现效果: 实现思路: ...
- Bug中的中的小问题编程需要注意
Bug中的中的小问题编程需要注意 1. 关于局部变量与全局变量是否同名问题 如果参数传递的是一个数组,且全局变量与参数数据同名,则局部变量作用域中,这两个同名的数据可能会引起冲突. 如下:如果一开始是 ...
- 音频算法之小黄人变声 附完整C代码
前面提及到<大话音频变声原理 附简单示例代码>与<声音变调算法PitchShift(模拟汤姆猫) 附完整C++算法实现代码> 都稍微讲过变声的原理和具体实现. 大家都知道,算法 ...
- FindBugs 入门——帮你减少代码中的bug数
FindBugs 入门 FindBugs 作用 开发人员在开发了一部分代码后,可以使用FindBugs进行代码缺陷的检查.提高代码的质量,同时也可以减少测试人员给你报的bug数. 代码缺陷分类 根据缺 ...
- 程序员怎样在复杂代码中找 bug?(简单)
分享下我的debug的经验 1. 优先解决那些可重现的,可重现的bug特别好找,反复调试测试就好了,先把好解决的干掉,这样最节约时间. 2. 对于某些bug没有头绪或者现象古怪不知道从哪里下手,找有经 ...
- 程序员新人怎样在复杂代码中找 bug?
分享下我的debug的经验 1. 优先解决那些可重现的,可重现的bug特别好找,反复调试测试就好了,先把好解决的干掉,这样最节约时间. 2. 对于某些bug没有头绪或者现象古怪不知道从哪里下手,找有经 ...
- Eclipse插件 - FindBugs 检查代码隐藏的 Bug
简介 FindBugs 是一个在 Java 程序中查找 bug 的程序,它可以查找可能出错的代码,注意 FindBugs 是检查 Java 字节码,也就是*.class文件.其实准确的 ...
随机推荐
- 2018-11-19-win10-uwp-使用-Matrix3DProjection-进行-3d-投影
title author date CreateTime categories win10 uwp 使用 Matrix3DProjection 进行 3d 投影 lindexi 2018-11-19 ...
- 【b801】笨小猴
Time Limit: 1 second Memory Limit: 50 MB [问题描述] 笨小猴的词汇量很小,所以每次做英语选择题的时候都很头疼.但是他找到了一种方法,经试验证明,用这种方法去选 ...
- ajax上传文件 基于jquery form表单上传文件
<script src="/static/js/jquery.js"></script><script> $("#reg-btn&qu ...
- 教你怎么让vi和vim显示行数
首先我们来看看没有行号是多么难看. 2 再来看看有行号后的效果. 3 设置行号很简单. 我们要到命令模式下,输入set number :set number 按下回车 来看看效果 4 那么怎么关闭行号 ...
- 模板——伸展树 splay 实现快速分裂合并的序列
伸展操作:将treap中特定的结点旋转到根 //将序列中从左数第k个元素伸展到根,注意结点键值保存的是原序列id void splay(Node* &o, int k) { ] == NULL ...
- Css布局常用 1.盒子内容局中 2. 物理一像素 3.倒三角形 绘制
布局 对象属性 new Person('') 原型链 (创建对象.使用对象中的属性,如果没有那么就去原型找) new Person() Person{ name:'', getname( ...
- Django入门9--Django shell
- 【u212】&&【t036】最大和
Time Limit: 1 second Memory Limit: 128 MB [问题描述] N个数围成一圈,要求从中选择若干个连续的数(注意每个数最多只能选一次)加起来,问能形成的最大的和. [ ...
- windows常用命令行命令
https://blog.csdn.net/qq_32451373/article/details/77743869 打开"运行"对话框(Win+R),输入cmd,打开控制台命令窗 ...
- P1043 查找小于x的最大元素
题目描述 现在告诉你一个长度为 \(n\) 的有序数组 \(a_1, a_2, ..., a_n\) ,以及 \(q\) 次询问,每次询问会给你一个数 \(x\) ,对于每次询问,你需要输出数组 \( ...