点击上方[全栈开发者社区]→右上角[...]→[设为星标⭐]
对于那些需要在浏览器中进行很多次点击才能重现的bug,用Selenium记录你点击的内容,并让Selenium重播UI交互(详细的建议请见这里:https://twitter.com/AnnieTheObscure/status/1142843984642899968);
如果你能够的话,编写一个重现错误的单元测试。这样做还有另外一个好处:如果这个单元测试有意义的话,你可以稍后将它添加到测试套件中;
编写一个脚本,或者找到一个命令行命令帮助你做它(比如curl MY_APP.local/whatever))。
我试着鼓励人们首先对这个bug有个全面的理解,比如说:什么正在发生?你期望会发生什么?什么时候会发生?什么时候不发生?然后运用他们对系统的心理模型来猜测可能发生的破坏,并进行实验。实验可以是更改或删除代码,从一个REPL调用API,尝试新的输入,使用调试器(debugger)或print语句来获取内存中的值。
猜测可能发生的错误的某一个方面(比如说,“这个变量被设置为X,它应该是Y”,或“发送到服务器的请求是错误的”,或“这段代码根本没有运行过”等等)。
做实验来验证这个猜测。
重复循环,直到你明白发生了根源所在。
此变量设置为X(“该文件名绝对正确”);
该变量的值不可能在X和Y之间变化;
这段代码以前没有问题;
此函数执行X;
我正在编辑正确的文件;
我写的那一行代码不可能有任何拼写错误,只是一行代码而已;
文档是正确的;
我正在查看的代码在某个时刻被执行;
这两段代码是按顺序执行的,而不是并行执行的;
这段代码在调试模式和发布模式下编译(使用或不使用-O2开关,或…)时,会做同样的事情;
编译器没有错误(这是故意放在最后的一个错误,很少有人会认为编译器会出错)。
在手机上添加声音:“在移动开发世界里,这条建议给了我很大帮助。Xcode可以在你遇到断点时播放声音(并且代码不停止而继续执行下去)。我把它们放在代码中的某个位置,然后听嗡嗡的叮当声来指示代码中发生的错误”(欲知详情,请查看上面提到的推文)。
关于使用Xcode播放iOS代码调试的声音,这里(https://qnoid.com/2013/06/08/Sound-Debugging.html)有一些很有趣的讨论。
添加发光二极管(LED):“很久以前,当我们在Transputer网格上做嵌入式开发时,我们将发光二极管连接到每个芯片的一个未使用的管脚上。它在诊断并行性问题上出奇地有效。”
string: “我的网络教授告诉我这样一个故事,在早期的以太网时代,他在施乐公司(Xerox)看到了一个黑客:他使用一个带有放大器,马达和一根绳子的同轴电缆接头。网络越忙,线就转得越快。”
Peep是一个“Network Auralizer”,可以将系统上发生的事情转换成声音。我花了10分钟试图让它编译,但迄今为止失败了,但它看起来很有趣,我想继续尝试它!!
可调试的代码并不一定干净,而充斥着检查或错误处理的代码很少能让人愉快地阅读。
if UNEXPECTED_THING:
raise "oh no THING happened"
获得正确的错误信息并不容易,因为你在程序当中哪里犯了错误并不总是显而易见的,但是这样做确实有很大帮助。
这比仅仅返回connection failure: timeout connecting to 1.2.3.4 port 1234本身要有用得多,因为它还告诉你和IP 1.2.3.4有关的其它一些重要的信息(比如上面这个错误就显示它和日志后端有关!)。我认为它也比返回带有堆栈跟踪信息的connection failure: timeout connecting to 1.2.3.4 port 1234的错误信息更加有用:因为它将堆栈跟踪信息中的关键的出错部分总结出来,这样你就不需要读取堆栈跟踪中的每一行(因为其中一些可能不相关!).
Go语言:它的习惯用法似乎是把你的一堆错误串成一个大字符串,这样你就得到了一长串的像这样的错误提示:“error:第一个错误:error:第二个错误:error:第二个错误”。它工作得很好,但是它的错误信息的结构比failure库能提供的要差得多。
Java语言:我听说Java可以给出异常的原因(Causes of exceptions), 但是我自己没有用过。
Python 3:你可以使用raise ... from设置异常的“__cause__”属性,然后你的异常将被这句话分开:The above exception was the direct cause of the following exception:..