提问人:MainID 提问时间:2/23/2009 最后编辑:Jay BazuziMainID 更新时间:7/27/2015 访问量:783
什么有助于提高发现错误的能力?
What helps to you improve your ability to find a bug?
答:
日志记录和单元测试。您掌握的有关所发生事件的信息越多,就越容易重现它。你使你的代码越模块化,就越容易检查它是否真的在你认为的地方行为不端,然后检查你的修复是否解决了问题。
单步执行代码,检查发生意外行为的流/状态。(当然,然后为它开发一个测试)。
我假设你的意思是逻辑错误。我发现捕获逻辑错误的最好方法是实现某种测试方案。查看 jUnit 作为标准。您几乎定义了一组可接受的方法输出。每次编译系统时,它都会检查所有测试用例。如果您引入了破坏测试的新逻辑,您将立即了解它并确切地知道必须修复的内容。
测试驱动设计是目前编程领域的一个相当大的运动。您将很难找到一种不支持某种测试的语言。甚至 JavaScript 也有大量的测试套件。
评论
我个人采取的方法是,在实际打开代码并查看之前,先考虑错误可能在代码中的位置。当你第一次开始使用这种方法时,它实际上可能不是很好,特别是如果你对代码库非常不熟悉。但是,随着时间的流逝,有人将能够告诉您他们正在经历的行为,并且您将很好地了解问题所在的位置,或者您甚至可能在查看代码之前就知道在代码中要修复什么来解决问题。
我从事一个由供应商维护的项目好几年了。他们不是很好的调试器,大多数时候,我们要把他们指向有问题的代码区域。更糟糕的是,我们没有一个很好的方法来查看源代码,所以我们的很多“调试”只是感觉。
在代码中编写 Debug.Write(message) 并使用 DebugView 是另一种选择。然后运行您的应用程序,找出发生了什么。
错误检查和报告。#1 新手编码器调试错误是关闭错误报告,避免检查正在发生的事情是否有意义等。一般来说,人们觉得如果他们看不到任何问题,那么就没有问题。当然,这与情况相去甚远。
相反,你的代码应该充满了错误条件,这些错误条件会发出很多噪音,并有详细的报告,你会在某个地方看到它。(这并不意味着在生产网页内。然后,不必到处跟踪错误,因为它在最终到达某个坏掉的地方之前经过了十六层执行,您的错误开始在实际问题附近发生。
这是发现错误后的预防方法:我发现花一分钟时间思考一下错误真的很有帮助。
- 本质上的错误到底是什么。
- 为什么会这样。
- 你能不能早点找到它,更容易。
- 你从错误中学到的任何其他东西。
我发现花一分钟时间考虑这些事情会大大降低您将来产生相同错误的可能性。
分而治之。每当进行调试时,都应该考虑减少问题的可能位置。每次运行应用程序时,您都应该尝试消除可能的来源并归零实际位置。这可以通过日志记录、调试器、断言等来完成。
软件中的“架构”是指:
- 几个组件
- 这些组件在明确定义的接口之间进行交互
- 每个组件都有明确定义的职责
- 一个组件的职责与其他组件的职责不同
所以,正如你所说,架构越好,就越容易发现错误。
首先:了解错误,您可以确定哪个功能被破坏,从而知道哪个组件实现了该功能。例如,如果 bug 是某些内容未被正确记录,则此 bug 应位于以下 3 个位置之一:
- 在负责日志记录的组件(日志记录库)中
- 或者,在使用此库的应用程序代码之上
- 或者,在此库使用的系统代码中低于此值
第二:检查组件之间通过接口传输的数据。要继续上面的前面示例,请执行以下操作:
- 在调用记录器 API 的应用程序代码上设置调试器断点,以验证记录器 API 是否被正确使用(例如,是否被调用,参数是否符合预期等)。
- 这样做会告诉您 bug 是在此接口上方的组件中,还是在在此接口下方的组件中。
- 重复(如果调用堆栈非常深,则可能使用二进制搜索),直到找到哪个组件有问题。
似乎你掌握的越多 软件的架构, 您可以更快地找到错误。
在了解了架构之后,人们在应用程序中发现错误的能力会随着他们识别和编写大量测试的能力而提高。
了解您的工具。
请确保了解如何在调试器中使用条件断点和监视。
也可以使用静态分析工具 - 它们可以指出更明显的问题。
经验使你成为更好的调试器。密切注意您和其他人经常犯的错误。试着弄清楚这些错误是否/如何适用于影响你的所有代码,而不是看到错误的单个实例。
雷蒙德·陈(Raymond Chen)以其通灵调试能力而闻名。
大部分看起来像通灵的东西 调试实际上只是知道什么 人们往往会犯错。
这意味着您不必非常熟悉架构/系统。您只需要足够的知识来了解适用且易于制作的错误类型。
- 首先使用产生更少错误的编程方法。
如果要实现单个独立的功能需求,则需要对源代码进行 N 次单独的点编辑,则放入代码中的错误数量大致与 N 成正比,因此请找到最小化 N 的编程方法。
- 在可能存在错误的地方,进行单元测试。
明显地。
恕我直言,最好的单元测试是蒙特卡洛。
- 使中间结果可见。
例如,编译器具有中间表示形式,采用 4 元组的形式。如果存在错误,可以检查中间代码。这告诉了错误是在编译器的前半部分还是后半部分。
P.S. 大多数程序员不知道他们可以选择使用多少数据结构。您使用的数据结构越少,由它引起的错误(和性能问题)的可能性就越小。
我发现跟踪点是一个非常宝贵的调试工具。它们有点像日志记录,只不过您在调试会话期间创建它们以解决特定问题,例如断点。
在跟踪点中打印堆栈跟踪可能特别有用。例如,可以在对象的构造函数中打印哈希代码和堆栈跟踪,然后稍后再次使用该对象时,可以搜索其哈希代码以查看哪个客户端代码创建了它。同样,看看是谁处理了它或调用了某种方法等。
它们也非常适合调试与窗口焦点更改等相关的问题,如果您进入中断模式,调试器会干扰。
静态代码工具,如 FindBugs
当你认为操作系统中一定存在错误时,请检查你的断言 - 并用“assert”语句将它们放入代码中。
相反,在编写代码时,请考虑算法的有效输入范围,并输入断言以确保您拥有您认为拥有的内容。输出也是如此:检查你是否生产了你认为你生产的东西。
例如,如果您期望一个非空列表:
l = getList(input)
assert l, "List was empty for input: %s" % str(input)
断言、断言和断言。
我们代码的某些区域对每行真实代码有 4 或 5 个断言。当我们收到错误报告时,首先发生的是客户数据在我们的调试版本中被处理了 99 次,其中 100 次,断言将在错误原因附近触发。
此外,我们的调试版本执行冗余计算,以确保优化的算法返回正确的结果,并且调试函数用于检查数据结构的健全性。
新开发人员必须面对的最困难的事情是让他们的代码在他们调用的代码断言中幸存下来。
此外,我们不允许将任何代码放回顶层,这会导致任何集成或单元测试失败。
睡觉和休息。
评论
我是 QA 团队 @ 工作的一员,对产品及其开发方式的了解对发现错误有很大帮助,而且当我制作新的 QA 工具时,我会将其传递给我们的开发团队进行测试,在您自己的代码中查找错误简直太难了!
有人说程序员被污染了,所以我们看不到他们自己产品中的错误;我们在这里不是在谈论代码,我们超越了可用性和功能本身。
同时,单元测试接缝是一个很好的解决方案,可以在你自己的代码中发现错误,如果你在编写单元测试之前就错了,那你就完全没有意义了,那么你将如何找到错误呢?你不要!,让你的同事找到他们,雇一个QA人员。
评论
科学调试是我一直使用的,它有很大的帮助。
基本上,如果你可以复制一个错误,你就可以跟踪它的来源。然后,您应该尝试一些测试,观察结果,并推断出错误发生原因的假设。
写下你所有的假设、尝试、预期结果和观察到的结果可以帮助你追踪错误,特别是当它们很讨厌的时候。
有一些自动化工具可以帮助你完成这个过程,特别是 git-bisect(以及其他修订系统上的类似平分工具),以快速找到哪个更改引入了错误,单元测试以重现错误并防止代码中的回归(可以与 bisect 结合使用)和增量调试找到代码中的罪魁祸首(类似于 git-bisect,但 git-bisect 处理代码历史记录,而增量调试直接处理代码)。
但无论你使用什么工具,最重要的好处是科学方法论,因为这是大多数有经验的调试器所做的事情的形式化。
评论