尊敬的 KV:
我刚花了一周的大部分时间调试一段代码中的问题,这段代码需要程序员——我——一遍又一遍地重新运行相同的 100 行代码,添加越来越多的调试语句,直到错误最终显现出来。由于这段特定的代码位于无服务器环境中,传统的调试器不是一种选择。相反,我不得不反复地触发该函数。最终,我会眼花缭乱,然后起身,在我的家庭办公室里走动,然后坐下来重新开始。我简直无法相信这是解决此类问题的正确方法,但是当我向团队的其他成员寻求帮助时,他们告诉我单调乏味是意料之中的。显然不可能是这样,对吗?
对单调乏味感到厌烦
亲爱的厌烦先生:
关于这个话题有太多的陈词滥调,我觉得我可以直接引用它们,给自己来一杯烈酒,然后就此结束。但这似乎太懒惰和不公平了,所以我还是先来一杯酒,并尽量避免陈词滥调。
我们大多数人都明白,计算机非常擅长一遍又一遍地做同样的事情。在糟糕的日子里,KV 感觉这似乎是计算机唯一真正擅长的事情,而他自己则被困在一个超现实的、苏斯博士式的噩梦般的景象中,其中奇怪地绘制、色彩鲜艳的角色胡说八道,同时导致我的所有代码以明显不可能的方式崩溃。不像我的一些同事,我不服用微剂量,所以我知道这是我的想象,我可以随时拉下噩梦的紧急制动器并逃脱,而无需等待剂量消退。
调试代码通常是迭代的,而迭代过程属于一遍又一遍的范畴。您运行函数,它给出错误的输出,您挠挠头思考,“哦,一定是 X”,然后您更改 X 并再次运行它,并得到另一个错误的结果。然后您想,“哦,不是 X,是 Y”,然后您将 X 改回去,然后尝试 Y,再次运行代码,然后...。沿着这条路走下去是疯狂,无论是否服用微剂量,但这在我们这个行业中是一条磨损严重的道路,我们都走过很多次。
有几种策略可以摆脱这条疯狂之路。
您已经暗示了摆脱疯狂之路的第一种方法,那就是使用调试器。不幸的是,世界上优秀的调试器太少了,程序员们也很少倾向于改善这种情况,因为——正如任何风险投资家都会告诉您的那样——在软件工具领域几乎没有钱可赚。
人们可能会认为,我们这些在行业内工作的人会为了我们自己的理智而致力于开发更好的调试器,但正如 KV 之前指出的那样,程序员是乐观主义者:我们总是认为这次我们做对了,我们可以编写更多代码,而不是调试我们现在面前的代码。这并不是说没有调试器;有,有些甚至可以工作——少数甚至工作得很好——但那些工作得好的调试器寥寥无几。
当 KV 看到代码中加载了调试语句时,他仍然咬牙切齿,如果编写代码的程序员能够对他们的调试器充满信心并熟练使用它们,这些调试语句将完全没有必要。如果一个人足够幸运能够使用好的调试器,那么他应该对他们通常感谢的任何事物表示极大的感谢,并使用该死的调试器!当 KV 还是一个年轻得多的程序员时,他为一个老板工作,这位老板坚持所有代码都必须首先在调试器中运行——当 KV 可以这样做时,他就会这样做。如果程序在调试器中运行良好,那么您可以尝试不使用辅助工具运行它,看看效果如何。
另一种摆脱疯狂之路的方法,也是可能与您这种无调试器环境最相关的方法,是在失败函数的每一行中添加某种形式的断言。作为程序员,您当然应该知道该函数应该做什么,所以断言它!一个好的语言会让您这样做,然后让您从视图中隐藏断言,但我很少看到有语言这样做。
更常见的情况是,有一个或 10 个断言库(因为人们太懒了,在自己动手编写之前,他们不会搜索他们需要的东西),您可以使用它们来做到这一点。不要走上迭代的疯狂之路,只对您认为导致错误的事情添加断言。断言函数中的每一行,然后——如果天随人愿——您将在下次运行代码时找到错误,因为您正在逐行检查函数的每一位。
最后,如果您正在与一个仅在 n 次中失败一次的函数作斗争,您将不得不利用计算机确实擅长一遍又一遍地做事的优势,并自动化失败函数的执行,以便您可以捕获失败。提升一个级别,编写一个循环,确保它可以捕获失败,然后回到——正如我所说——调制一杯好的烈酒。KV 是 Vesper 马提尼的粉丝,但他可以证明,如果他正在寻找的失败是间歇性的,他可以喝大约六杯这种酒,到那时,好吧,调试就不再是他脑海中的事情了。干杯!
KV
责任外包
当你的调试器让你失望时,你会怎么做?
https://queue.org.cn/detail.cfm?id=2639483
肆意妄为的调试行为
保持您的调试消息清晰、有用且不烦人。
https://queue.org.cn/detail.cfm?id=2048938
在生产系统上调试
这更多的是一个社会问题,而不是技术问题。
https://queue.org.cn/detail.cfm?id=2031677
Kode Vicious,凡人称之为 George V. Neville-Neil,为了乐趣和利润而从事网络和操作系统代码方面的工作。他还教授各种与编程相关的科目。他的兴趣领域是代码探险、操作系统和重写您的糟糕代码(好吧,也许不是最后一个)。他获得了马萨诸塞州波士顿东北大学计算机科学学士学位,并且是 、Usenix 协会和 IEEE 的成员。Neville-Neil 与 Marshall Kirk McKusick 和 Robert N. M. Watson 合著了《FreeBSD 操作系统设计与实现》(第二版)。他是一位狂热的自行车爱好者和旅行者,目前居住在纽约市。
版权 © 2021 由所有者/作者持有。出版权已许可给 。
最初发表于 Queue vol. 19, no. 6—
在 数字图书馆 中评论本文
Charisma Chan, Beth Cooper - 调试 Google 分布式系统中的事件
本文介绍了 2019 年对 Google 工程师如何调试生产问题进行的研究结果,包括工程师在不同组合中使用的工具类型、高层策略和底层任务,以有效地进行调试。它考察了用于捕获数据的研究方法,总结了生产调查的常见工程历程,并分享了专家如何调试复杂分布式系统的示例。最后,本文将这项研究的 Google 特性扩展到提供一些您可以在组织中应用的实用策略。
Devon H. O'Dell - 调试思维模式
软件开发人员花费 35-50% 的时间来验证和调试软件。调试、测试和验证的成本估计占软件开发项目总预算的 50-75%,每年超过 1000 亿美元。虽然工具、语言和环境减少了花费在单个调试任务上的时间,但它们并没有显着减少花费在调试上的总时间,也没有减少调试的成本。因此,过度关注开发过程中消除错误是适得其反的;程序员应该拥抱调试作为一种解决问题的练习。
Peter Phillips - 使用跟踪增强调试
创建一个模拟器来运行旧程序是一项艰巨的任务。您需要彻底了解目标硬件以及模拟器要执行的原始程序的正确功能。除了功能正确之外,模拟器还必须达到以原始实时速度运行程序的性能目标。实现这些目标不可避免地需要大量的调试。错误通常是模拟器本身中的细微错误,但也可能是对目标硬件的误解或原始程序中实际存在的已知错误。(原始程序的二进制数据也可能变得轻微损坏或不是预期的版本。)
Queue Readers - 又一天,又一个 Bug
作为本期关于程序员工具的一部分,我们在 Queue 决定就调试主题进行一项非正式的网络投票。我们要求您告诉我们您使用的工具以及您如何使用它们。我们还收集了关于那些难以追踪的错误的故事,这些错误有时会让我们想到从事其他职业。