调试规则
这是生活中的现实:您将花费大部分的编码时间进行调试。
如果你已经在这方面投入了一段时间,那么你可能已经把调试变成了一门艺术。对于其他人来说,这里有一些来自实践的规则:
规则一:不要假设任何事。绝对不要假设任何事。
除非你掌握了所有数据,否则你无法解决问题。切勿掉以轻心!检查所有相关变量的值。仔细阅读堆栈跟踪。单步执行你的代码。
十有八九,错误会隐藏在问题中你认为可以理所当然的一个区域。
我也喜欢约翰·卡马克的说法......
大多数错误都是由于执行状态与您想象的不完全一致而导致的。
顺便说一句:永远不要向任何帮助你调试的人隐瞒所有这些信息。向他们展示正在运行的代码和数据,以及所有输出和错误消息的详细信息。要慷慨。隐瞒信息会浪费每个人的时间。
规则二:问题出在你身上,除非有证据证明不是你。
人们很容易就得出结论,认为库、语言、环境、工具或其他什么东西出了 bug。但实际上,你在别人的代码中发现一个 bug,通常就能在自己的代码中发现至少一百个。
假设你的代码有问题,除非你能绝对、量化地证明并非如此。找人检查你的代码。阅读文档。尝试在不同的环境中复现问题。如果你确定问题不在你的代码上,请再次检查。
规则#3:代码失败的方式数量理论上是无限的。
如果我可以这么大胆,我真想把它称为麦当劳第一定律。它值得重复。
理论上,代码失败的方式是无限的。
我自己的代码总能以如此多新奇有趣的方式彻底崩溃,这总是让我惊叹不已。这也是为什么你会认为问题出在自己身上(规则二)的另一个原因——即使你已经涵盖了所有可能出现的异常状态或失败情况,仍然可能出现其他情况。一旦加上其他人代码的不可预测性,你的一生都将充满惊喜。
如果你每年没有至少一次盯着电脑屏幕大喊“这到底是怎么回事?”或类似的话,那你就做错了。
规则#4:复杂性是你的敌人。
真正的代码很复杂。这就是为什么调试它如此痛苦!当你遇到一个特别困难的问题时,创建一个最小、完整、可验证的示例(用 StackOverflow 的术语来说,就是 MCVE)会很有帮助。
在一个相对新鲜的环境中,用尽可能少的代码和依赖项来复现问题。如果成功了,就继续添加细节,直到问题彻底解决。你最后做的任何事情几乎肯定都是问题的一部分!
规则#5:如果它很奇怪,那就是记忆。
这不仅仅适用于像 C 和 C++ 这样“锋芒毕露”的语言,在这些语言中,你可以随心所欲地摆弄代码。任何来自用户之外的、包含彻底垃圾代码的 bug,几乎肯定与内存错误有关。
未定义行为和内存错误是所有现代编程赖以生存的堆栈的核心。翻翻你最喜欢的语言的异常列表,你几乎肯定会发现一些与内存相关的内容。
现在,如何实际检测和修复所述内存错误完全取决于您的语言和平台。
规则#6:您可能在某处忘记了分号。
有一次,我花了两天时间试图修复代码中的一个无限循环。我当时正抓狂不已,几乎要怀疑我的电脑是不是被某种邪恶力量控制了,这时我妈妈走进了房间。
她盯着屏幕看了一会儿,然后指着屏幕说:“第56行中间不需要加分号吗?”
我妈不是程序员。可是,你猜我在第56行忘了什么?一个分号。
此后的几年里,我发现很多可怕而神秘的 bug 都是因为缺少一些标记:分号、逗号、反斜杠、空格。“有效代码”和“正确代码”之间存在着巨大的鸿沟,我们每个人每周至少都会有一次无法像埃维尔·克尼维尔那样跨越这个鸿沟。
很可能你自己都发现不了这些小错误。我们都是代码盲!如果几分钟后你还是没发现,那就找个程序员帮你看看,然后好好笑一笑你的愚蠢错误。你会犯很多这样的错误。
规则7:永远不要低估傻瓜的聪明才智。
如果你想知道的话,完整的引文是……
“人们在尝试设计万无一失的东西时常犯的一个错误就是低估了傻瓜的聪明才智。”——道格拉斯·亚当斯
迟早,你那不可抗拒的代码力量会遭遇你那无情的愚蠢用户。(别嘲笑……说不定,那个用户就是凌晨两点咖啡因不足的你。)湿件臭名昭著地漏洞百出:最终,有人会要求你的代码做一些违背物理、数学和常识的事情。
为了防止这种情况,我们编写了绝对阴险的测试:
“QA 工程师走进一家酒吧。点了一杯啤酒。点了 0 杯啤酒。点了 999999999 杯啤酒。点了一只蜥蜴。点了 -1 杯啤酒。点了一杯 sfdeljknesv。”——Bill Sempf
正如人们所说,“最好的防守就是进攻”,这句话也适用于调试。尽可能多地想出巧妙的方法来破坏你的代码。看看当你输入垃圾输入时会发生什么。打破你自己的 API 规则。打开界面,然后让你的猫坐在你的键盘上。简而言之,对你的代码做一些可怕的事情。
(PS:关于猫的事,我可没开玩笑。我的一个编程朋友养了一只猫,它居然坐在我朋友腿上睡觉的时候,以 85% 的成绩通过了业余无线电执照的模拟考试。我是认真的。)
规则#8:旧式纸张是你最好的朋友。
现代程序员拥有丰富的调试工具:调试器、静态分析器、内存检查器、代码分析器、测试框架等等!但不要忽视地球上最古老、最可靠的调试工具——一张纸、一支铅笔和你自己的眼睛。
所谓的“桌面检查”是一种极其宝贵的工具。虽然你可以用各种复杂的工具连续几个小时苦苦追寻目标,但没有什么比自己阅读代码、记录每个变量的变化值、进行数学运算、评估每个逻辑语句更有效了。你不仅可以很好地练习像计算机一样思考,还会惊讶于自己能够如此迅速地找到问题所在。
桌面检查是我个人的第一道防线,我会在调试器之前或调试时使用它。用这种方法,我避免了好几个小时的困惑和心痛。
规则#9:你正在寻找的那个虫子很可能就是 Jabberwocky。
编程很奇怪。出于我们尚不完全理解的原因,软件并不一定遵循数学或物理定律。有时,它似乎有自己的想法。
请考虑以下内容,全部取自 Jargon File:
heisenbug (n):当人们尝试探测或隔离它时,它会消失或改变其行为。
mandelbug(n):一种错误,其根本原因非常复杂且不明显,以致其行为显得混乱甚至不确定。
schroedinbug (n):程序中的设计或实现错误,只有在有人阅读源代码或以不寻常的方式使用程序时才会显现出来,注意到它根本不应该运行,此时程序就会立即停止为所有人运行,直到修复为止。
虽然听起来有些神秘,但它们确实真实存在。我实际上在野外观察并证实过所有这些现象至少一次。
简而言之,一生的调试工作肯定会带来一些匪夷所思的故事。虽然大多数 bug 都是玻尔 bug(也就是说,它们在一组明确定义的条件下出现),而且大多数都是你的错(规则 2),但也要做好应对各种奇葩情况的准备。永远不要想当然地认为你懂计算机。
这让我得出一个重要的推论:你的计算机会把所有对时间和难度的估计都视为个人挑战。如果你说“实现 X 很容易”或“我只需要一个周末就能完成 Y”,那么你几乎可以肯定你的代码会充满怪异之处。
例如,我曾经估计一个项目只需要一周时间。结果却需要四位开发人员耗时三年才能完成。(这个项目上个月才刚刚完成。)
欢迎来到编程世界。进入兔子洞时请注意家具。
规则#10:您是否已将其关闭并再次打开?
听起来可能有点傻,但这种方法确实比你想象的要管用,即使软件出了bug!我试了一段时间,确认问题不是出在我身上后,就重启了电脑。有好几次,这种方法彻底解决了问题,之后再也没出现过。
然而……这一点非常重要……你必须先排除自己是问题所在。麻省理工学院的一篇传奇人工智能公案探讨了这一现象:
一名新手试图通过关闭和打开电源来修复损坏的 Lisp 机器。
奈特看到这名学生的行为后,严厉地说道:“如果你不了解问题所在,就无法通过简单地关闭电源来修理机器。”
奈特关闭了机器,然后又打开。
机器运转了。
规则#11:如果其他方法都失败了,那就和鸭子说话。
作者注:我原本计划写10条规则,但编号时少了一条。当然,关于调试的文章肯定会有bug。
橡皮鸭思维在开发者中很流行,而且理由充分。通常,只要大声说出来就能帮你从不同的角度处理问题,最终找到解决方案。为此,很多程序员都会在办公桌上放一只橡皮鸭。
别忘了,不一定非得是橡皮鸭。我用的是 Funko 的 Doctor Whooves 乙烯基玩偶(出自《我的小马驹:友谊就是魔法》)。随便你,随便你……或者鸭子。
你的编程生涯大部分时间都会花在调试上,而且你将会发现哪些匪夷所思的事情,无人可知。你将探究人类愚蠢的深度(尤其是你自己的愚蠢),体验应用数学被激怒的原始力量,并在时空连续体中戳出不少明显的漏洞。假设你活了下来,你将有很多故事可以讲给你的孩子们听。
我将用《塞尔达传说》中那些不朽却被错误引用的话语来结束这段往事:
文章来源:https://dev.to/codemouse92/the-rules-of-debugging-2hf5独自前往很危险.........那么,祝你好运!