尊敬的KV:
为什么人们在程序中添加日志时,缺乏区分日志消息的创造力?如果它们都说同样的事情——例如,DEBUG——就很难分辨正在发生什么,甚至不明白之前的程序员最初为什么要添加这些语句。
相似性之苦
尊敬的痛苦者:
来自程序的无差别噪声就像指甲划过黑板的声音:它既烦人又无用,并在听者心中产生一种本能的需求,想要让它停止,必要时甚至采取暴力手段。当然,没有哪个理智的程序员会在一个实例中添加相同的调试语句。所有软件项目的持续时间都比最初的设计者认为的要长。与许多困扰长期软件项目的问题一样,调试语句就像船底的藤壶一样积聚。就像藤壶一样,它们也必须不时地刮掉。具有现代奥威尔式倾向的人称之为“重构”;我更喜欢称之为“清理你早就应该清理的垃圾”。如果你非常幸运,那么所有这些语句都包含在某种条件编译指令或if (debug)
语句下。如果它们只是散落在代码中,那么你已经遇到了更大的问题,因为最初的编码员要么是疯了,要么是无能。
好的调试语句有几个共同点。第一个要求是它们可以被关闭。许多父母说孩子应该被看到而不是被听到,软件也是如此。如果你没有积极地调试系统,那么你不应该看到调试输出飞快地闪过或被随意地转储到日志文件中。其次,就像你将要放入程序中的任何其他代码一样,调试语句需要有意义。
在之前的专栏(“文件系统垃圾”,2011年7月;)中,我展示了一个简单的Emacs宏,用于插入调试语句,在C和C++中,它会显示程序正在执行的文件中的哪一行。知道你刚刚经过哪个程序语句是应该严格临时的调试日志类型,而且我认为永远不应该将其签入到源代码仓库中。一旦最初的程序员继续执行另一项任务,这种东西就会被遗忘,一旦被遗忘,当再次发现时会引起极大的烦恼。如果你真的要保留一个调试语句,那么它应该比简单的行和文件更具描述性。它需要说明它在那里是为了什么:这是一个 критическая 错误吗?它是否表明存在需要人工干预的问题?
这两个问题引出了我的下一个要求,即级别。如果你不按级别细分调试消息,那么对于以后运行你的软件的人来说,所有这些消息都将显得至关重要,从而引起极大的恐慌。现在大多数程序员都对他们的调试消息进行区分,以便它们可以分为少量类别:信息、警告和错误。信息消息是信息性的;它只是告诉某人有关程序状态的信息,但并不意味着程序犯了错误,也不意味着需要人为干预。警告比信息消息更严重,通常表明需要有人了解程序的状态。警告的良好目标是及早指示资源(如磁盘空间或内存)正在耗尽,并且某种形式的人工干预(如移动或删除旧日志文件)可以清除问题。错误就是这样——程序中的错误。错误显然没有导致程序崩溃,但有些事情出了问题,以至于需要有人介入并清理程序造成的任何混乱。在某些系统中,例如实时控制系统,错误会停止程序,但是正如现代桌面和服务器软件的用户所熟知的那样,许多系统会记录错误,然后愉快地返回到执行错误发生之前正在执行的任何操作。
现在我们有了一组合理的可能调试消息,让我谈谈在问题确实发生时如何让人们参与进来。在我的一生中,我认识许多优秀的系统管理员,他们最不喜欢的事情就是让某些程序在凌晨3点无缘无故地叫醒他们。事实上,如果你的软件“狼来了”的次数太多,他们会诅咒你和你的软件。太多通常以个位数的凌晨3点叫醒电话来衡量。如果你要插入一条调试消息,即使有唤醒某人半夜的微小可能性,你也最好绝对确定它将很重要,而且如果这是一个可以清除的错误,那么被唤醒的人可以清除它然后回去睡觉。你见过凌晨9点会诊会议上红眼睛的系统管理员吗?如果你见过,那么你就知道你不想再看到这种情况。如果你要以需要人注意的方式记录问题,那么你最好绝对确定他们惹恼的人可以关闭它们。
KV
尊敬的KV:
为什么公司在测试硬件方面如此吝啬?我刚刚花了两个星期在半夜调试一个程序,因为我们购买的新硬件仅在我们的生产系统中可用。如果我在部署之前有这个硬件进行测试,问题本可以在一半的时间内解决。
整夜奋战者
亲爱的整夜奋战者:
如果我告诉你,早在我成为程序员之前,几乎所有的调试都是在半夜进行的,因为硬件既昂贵又稀有,这可能不会让你感觉好些。除非该错误本身阻止了工资单程序的运行,否则你不能停止运行工资单程序只是为了让某人尝试修复系统中的错误。
当然,在我们目前硬件廉价且充足的情况下,反对购买测试硬件的理由较少。如果我正在与一个特别吝啬的客户打交道,我只会将测试硬件标记为“备件”,这是一个简单的诡计,让会计师感到高兴。每个人都知道东西会坏,而且你肯定不想等一个星期才能等到备件出现,所以你必须将它们放在手边——在你附近的测试系统中。
但是,仍然有一些时候,某些深奥的硬件会太贵而无法作为备件订购。这是我估计“太贵”的标准的方法。如果一件硬件的成本超过你年薪的50%,那么购买测试版本可能太贵了;如果低于这个比例,那么就该与管理层谈判了,因为你的时间也值钱。问题是许多公司没有认识到这一事实,因为会计部门不跟踪工时,但他们确实注意到每件硬件的成本是多少。如果你每年赚100,000美元,这是一个并非不可能的数字,那么你的时薪约为50美元。如果修复一个问题需要两个星期,那就是80小时,或4,000美元。如果问题可以在一半的时间内解决,即40小时,那么公司可以节省2,000美元。谢天谢地,大多数工程师不再需要填写时间表,但关注你的时间成本仍然有意义——特别是,如果你试图说服管理层购买他们认为是一项额外成本的硬件。
当我在新硬件的软件上工作时,我总是将测试硬件纳入项目预算,因为正如你已经看到的那样,这比熬夜修复生产中的问题要好。哦,不要相信硬件供应商说新硬件就像旧硬件一样,只是更好、更强大或更快。他们的说法可能是真的,但也同样有可能暴露你已部署代码中的错误。确保也为新版本获取测试硬件。
KV
KODE VICIOUS,凡人称之为 George V. Neville-Neil,为乐趣和利润从事网络和操作系统代码的工作。他还教授与编程相关的各种主题的课程。他的兴趣领域是代码探险、操作系统和重写你的糟糕代码(好吧,也许不是最后一个)。他获得了马萨诸塞州波士顿东北大学计算机科学学士学位,并且是 、Usenix 协会和 IEEE 的成员。他是一位狂热的自行车爱好者和旅行家,目前居住在纽约市。
© 2011 1542-7730/11/1000 $10.00
最初发表于 Queue vol. 9, no. 10—
在 数字图书馆 中评论本文
Charisma Chan, Beth Cooper - 在 Google 的分布式系统中调试事件
本文介绍了 2019 年对 Google 工程师如何调试生产问题的研究成果,包括工程师在不同组合中使用以有效调试的工具类型、高级策略和低级任务。它考察了用于捕获数据的研究方法,总结了生产调查的常见工程历程,并分享了专家如何调试复杂分布式系统的示例。最后,本文扩展了这项研究的 Google 特性,以提供一些你可以在你的组织中应用的实用策略。
Devon H. O'Dell - 调试心态
软件开发人员花费 35-50% 的时间来验证和调试软件。调试、测试和验证的成本估计占软件开发项目总预算的 50-75%,每年超过 1000 亿美元。虽然工具、语言和环境减少了在单个调试任务上花费的时间,但它们并没有显着减少调试的总时间,也没有减少调试的成本。因此,过度关注开发期间消除错误是适得其反的;程序员应该将调试视为一种解决问题的练习。
Peter Phillips - 使用跟踪增强调试
创建用于运行旧程序的模拟器是一项艰巨的任务。你需要透彻了解目标硬件以及模拟器要执行的原始程序的正确功能。除了功能正确之外,模拟器还必须达到以原始实时速度运行程序的目标性能。实现这些目标不可避免地需要大量的调试。错误通常是模拟器本身中的细微错误,但也可能是对目标硬件的误解或原始程序中的实际已知错误。(原始程序的二进制数据也可能变得稍微损坏或不是预期的版本。)
Queue Readers - 又一天,又一个 Bug
作为本期关于程序员工具的一部分,我们在 Queue 决定就调试主题进行一项非正式的网络调查。我们请你告诉我们你使用的工具以及你如何使用它们。我们还收集了关于那些难以追踪的错误的故事,这些错误有时会让我们想到从事其他职业。