您如何解决无法复制的错误?


67

问题说明了一切。如果您有一个由多个用户报告的错误,但是在日志中没有记录该错误的记录,也无法重复该错误,无论您如何努力,如何解决它?甚至可以吗?

我相信这已经发生在你们当中的许多人身上。在这种情况下,您做了什么?最终结果是什么?


编辑:我更感兴趣的是做关于unfindable的bug,而不是一个无法解决的错误。无法解决的错误使您至少知道存在问题,并且在大多数情况下有一个搜索起点。如果情况不佳,该怎么办?你什至可以做什么?



1
问我最后的老板。他似乎确信我应该能够修复无法复制的错误。
迪纳

1
stackoverflow.com/questions/154897/…使用术语“解决”,但是问题显然是关于无法复制的问题。
约翰·桑德斯

人们的观点是,实际上几乎不可能实现无缺陷软件(至少在可能由数学证明的小型算法之外),而不是有人以某种方式想要软件中的缺陷。其余的观点是,对于PM的不切实际的期望,人们无能为力。
MatthewMartin 2011年

Answers:


83

语言

不同的编程语言将具有自己的错误样式。

C

添加调试语句可以使问题无法被复制,因为调试语句本身移动指针远远不够,以避免段错误---又称Heisenbugs。指针问题很难跟踪和复制,但是调试器可以提供帮助(例如GDBDDD)。

爪哇

具有多个线程的应用程序可能仅以非常特定的时序或事件序列显示其错误。不适当的并发实现可能在难以复制的情况下导致死锁。

的JavaScript

一些Web浏览器因内存泄漏而臭名昭著。在一个浏览器中运行良好的JavaScript代码可能会在另一浏览器中导致不正确的行为。使用经过成千上万的用户严格测试的第三方库,对于避免某些难以理解的错误可能是有利的。

环境

根据运行该应用程序(具有错误)的环境的复杂性,唯一的办法可能是简化环境。应用程序是否运行:

  • 在服务器上?
  • 在桌面上?
  • 在网络浏览器中?

应用程序在什么环境下会产生问题?

  • 发展?
  • 测试?
  • 生产?

退出无关的应用程序,终止后台任务,停止所有计划的事件(定时作业),消除插件,并卸载浏览器加载项。

联网

由于联网对于许多应用程序都是必不可少的:

  • 确保稳定的网络连接,包括无线信号。
  • 网络故障发生后,软件是否可以重新连接?
  • 是否所有连接都正确关闭以释放文件描述符?
  • 人们在使用机器吗?
  • 流氓设备是否与机器的网络交互?
  • 附近是否有工厂或无线电塔会造成干扰?
  • 数据包的大小和频率是否在标称范围内?
  • 是否监视数据包的丢失
  • 所有网络设备是否都适合高带宽使用?

一致性

消除尽可能多的未知数:

  • 隔离架构组件。
  • 删除不必要的或可能有问题的(冲突的)元素。
  • 停用不同的应用程序模块。

消除生产,测试和开发之间的所有差异。使用相同的硬件。完全按照完全相同的步骤安装计算机。一致性是关键。

记录中

使用大量的日志记录来关联事件发生的时间。检查日志中是否有任何明显的错误,计时问题等。

硬件

如果软件看起来还可以,请考虑硬件故障:

  • 物理网络连接是否牢固?
  • 电缆是否松动?
  • 筹码放置正确吗?
  • 所有电缆的连接是否干净?
  • 工作环境清洁无尘吗?
  • 啮齿动物或昆虫是否损坏了任何隐藏的设备或电缆?
  • 驱动器上是否有坏块?
  • CPU风扇在工作吗?
  • 主板可以为所有组件供电吗?(CPU,网卡,视频卡,驱动器等)
  • 可能的电磁干扰是罪魁祸首?

主要用于嵌入式:

  • 旁路供应不足?
  • 电路板污染?
  • 焊点不良/回流不良?
  • 电源电压超出公差范围时,CPU是否无法复位?
  • 复位不好,因为供电轨由I / O端口供电并且没有完全放电?
  • 闭锁?
  • 浮动输入引脚?
  • 逻辑电平上的噪声余量不足(有时为负)?
  • 时序余量不足(有时为负)?
  • 锡晶须
  • ESD损坏?
  • ESD问题?
  • 芯片勘误表?
  • 接口滥用(例如,板外I2C或存在大功率信号)?
  • 比赛条件?
  • 假冒零件?

网络与本地

当您在本地运行该应用程序(即不在整个网络中)时会发生什么?其他服务器是否遇到相同的问题?数据库是远程的吗?可以使用本地数据库吗?

固件

硬件和软件之间是固件。

  • 电脑的BIOS是最新的吗?
  • BIOS电池可以工作吗?
  • BIOS时钟和系统时钟是否同步?

时间和统计

时间问题很难跟踪:

  • 问题什么时候发生?
  • 多久一次?
  • 当时还运行哪些其他系统?
  • 应用程序是否对时间敏感(例如,leap日或leap秒会导致问题)?

收集有关该问题的硬数字数据。一开始可能是随机出现的问题,实际上可能有一个模式。

更换管理层

有时,系统升级后会出现问题。

  • 问题何时开始?
  • 环境(硬件和软件)发生了什么变化?
  • 回滚到以前的版本后会发生什么?
  • 有问题的版本和良好的版本之间存在什么区别?

图书馆管理

不同的操作系统具有不同的分发冲突库的方式:

  • Windows具有DLL Hell
  • Unix可以具有许多断开的符号链接。
  • Java库文件可能同样难以解决。

重新安装操作系统,并仅包括应用程序所需的支持软件。

爪哇

确保每个库仅使用一次。有时,应用程序容器的库版本与应用程序本身不同。这可能无法在开发环境中复制。

使用库管理工具,例如MavenIvy

调试

编写检测方法,以在错误发生时触发通知(例如,日志,电子邮件,弹出窗口,寻呼机蜂鸣声)。使用自动测试将数据提交到应用程序中。使用随机数据。使用涵盖已知和可能的极端情况的数据。最终,该错误应重新出现。

睡觉

值得重申的是其他人提到的:睡在上面。花点时间解决问题,完成其他任务(例如文档)。与计算机保持距离并进行一些运动。

代码审查

逐行浏览代码,并描述每一行对您自己,同事或橡皮鸭的所作所为。这可能会导致有关如何重现该错误的见解。

宇宙辐射

宇宙射线可以翻转位。由于内存的现代错误检查,这已不再像过去那样大。由于宇宙辐射的随机性,离开地球保护的硬件软件存在一些根本无法复制的问题。

工具类

有时(尽管很少),编译器会引入一个错误,尤其是针对小众工具(例如,遭受符号表溢出的C微控制器编译器)的错误。是否可以使用其他编译器?工具链中的任何其他工具都会引入问题吗?


13

如果它是一个GUI应用程序,那么观看客户产生错误(或尝试这样做)是非常宝贵的。他们无疑会在做您从未想过的事情(没错,只是有所不同)。

否则,将您的日志集中在该区域。记录所有内容(您可以稍后将其取出),并使您的应用程序也转储其环境。例如,机器类型,VM类型,使用的编码。

您的应用是否报告版本号,内部版本号等?您需要使用它来精确确定要调试的版本(或不!)。

如果您可以检测您的应用程序(例如,如果您在Java世界中,则使用JMX),然后检测相关区域。存储统计信息,例如请求+参数,时间等。利用缓冲区存储最后的'n'个请求/响应/对象版本/所有内容,并在用户报告问题时将其转储出去。


8

如果您无法复制它,则可以对其进行修复,但不知道已对其进行了修复。

我已经就如何触发该错误做出了最好的解释(即使我不知道这种情况如何发生),也对此进行了修复,并确保如果该错误再次出现,我们的通知机制将使将来的开发人员知道我希望知道的事情。实际上,这意味着在跨越可能触发该错误的路径并记录相关资源的度量时,添加日志事件。并且,当然,要确保测试总体上很好地执行了代码。

确定添加哪些通知是一个可行性和分类问题。因此,首先要确定开发人员要花多少时间在bug上。不知道该错误的重要性是无法回答的。

我有很好的结果(没有再次出现,代码对此也更好),也有不好的结果(花了太多时间不解决问题,不管错误是否最终得以解决)。这就是估计和问题优先级的目的。


2
我做了一次。我设法确定了该错误在代码行中的位置,对其进行了修复,仅是因为由于该错误的第二个实例位于500行之外,所以才将其修复。
约书亚州

7

有时,我只需要坐下来研究代码,直到找到错误为止。尝试证明该错误是不可能的,在此过程中,您可能会弄清楚您可能在哪里犯了错误。如果您实际上成功说服了自己,那是不可能的,那就假设您搞砸了。

添加一堆错误检查和断言来确认或否认您的信念/假设可能会有所帮助。某些您可能无法预期的失败。


6

这可能很困难,有时几乎是不可能的。但是我的经验是,如果您花了足够的时间(或花费的时间是值得的,那是另一回事),您迟早将能够重现并修复该错误。

在这种情况下可能会有帮助的一般建议。

  • 如果可能的话,添加更多的日志记录,以便下次出现该错误时可以拥有更多的数据。
  • 询问用户是否可以复制该错误。如果是,您可以让他们在看着他们的肩膀的同时复制它,并希望找出导致该错误的原因。

是的-不是十分钟前我接到电话,看来有人终于设法重现了我只是怀疑但并不确定多年的错误。这种情况每年可能出现两次,永远无法重现,观察到的行为可能总是由于过去默默加载的价格变化所致。
罗伦·佩希特尔

“添加更多日志”。这是正确的答案。如果您有权修复错误,那么您也可能有权使代码自我报告其错误。我已经看到开发人员变得害怕进行大刀阔斧的代码更改,就好像他们永远被继承的无法诊断的代码所困。如果代码以静默方式失败,则该静默是您需要修复的第一个错误。您(作为开发人员)在这方面是相关的利益相关者。
durette


4

认为。硬。把自己锁起来,不要插手。

我曾经有一个错误,即证据是损坏的数据库的十六进制转储。指针链被系统地弄砸了。所有用户程序和我们的数据库软件在测试中均能正常工作。我盯着它看了一个星期(它是一个重要的客户),在消除了数十种可能的想法之后,我意识到数据分散在两个物理文件中,并且损坏发生在链条跨越文件边界的地方。我意识到,如果备份/还原操作在关键时刻失败,则两个文件可能最终“不同步”,并恢复到不同的时间点。然后,如果您在已经损坏的数据上运行客户程序之一,它将完全生成我所看到的打结的指针链。然后,我演示了一系列事件,这些事件准确地再现了损坏。


3

在您认为发生问题的地方修改代码,以便在某处记录额外的调试信息。下次发生时,您将拥有解决问题的需要。


3

您无法复制两种错误。您发现的种类以及其他人发现的种类。

如果发现该错误,则应该能够复制它。如果您无法复制它,那么您根本就不会考虑导致该错误的所有因素。这就是为什么每当有错误时都应记录下来。保存日志,获取屏幕截图,等等。如果您不这样做,那么如何证明错误确实存在?也许只是一个错误的记忆?

如果其他人发现了错误,并且您无法复制它,则显然要求他们复制它。如果他们无法复制它,那么您尝试复制它。如果您无法快速复制它,请忽略它。

我知道这听起来很糟糕,但我认为这是有道理的。复制别人发现的错误所需的时间非常长。如果该错误是真实的,它将自然再次发生。有人,甚至您,都会再次跌倒。如果很难复制,那么它也是很少见的,如果再重复几次,可能不会造成太大的损害。

如果您花时间在实际上工作,修复其他错误并编写新代码,则可能会比尝试复制甚至无法保证实际存在的神秘错误要多得多。只需等待它再次自然出现,您就可以花费所有时间修复它,而不用浪费时间尝试揭示它。


取决于后果的严重程度。每年大约发生一次的银行无声地将货币值移动到小数点后一位的bug肯定会引起很多问题,无论它多么罕见。
2009年

3

假设您已经添加了您认为会帮助并且没有帮助的所有日志记录,那么请记住两点:

  1. 从报告的症状向后工作。想一想。“我想产生所报告的症状,我需要执行什么代码,我将如何去做,以及我将如何去做?” D导致C导致B导致A。接受如果错误不可复制,那么常规方法将无济于事。这些类型的思考过程一直在寻找一些错误,我不得不盯着代码看了好几个小时。通常,事实证明这确实是愚蠢的。

  2. 记住鲍勃调试的第一法则:如果找不到东西,那是因为您在错误的地方寻找:-)


2

讨论问题,阅读代码,通常很多。通常我们会成对进行,因为您通常可以在分析上迅速消除这种可能性。


2

首先查看您可以使用的工具。例如,在Windows平台上发生崩溃,请转到WinQual,因此,如果遇到这种情况,您现在可以获得崩溃转储信息。您是否可以找到潜在错误的静态分析工具,运行时分析工具,性能分析工具?

然后查看输入和输出。在用户报告错误的情况下,输入内容有何相似之处,或输出内容有何不正确之处?编译报告列表并查找模式。

最后,正如大卫所说,盯着代码。


1

要求用户为您的计算机提供远程访问权限,然后自己查看一切。要求用户制作一个关于如何重现此错误的小视频,并将其发送给您。

当然,这两种方法并非总是可能的,但是如果可以的话,这可能会澄清一些事情。查找错误的常见方法仍然是相同的:分离可能导致错误的部分,试图了解正在发生的事情,缩小可能导致错误的代码空间。


0

有诸如gotomeeting.com之类的工具,可用于与用户共享屏幕并观察行为。可能存在许多潜在问题,例如计算机上安装的软件数量,某些工具实用程序与您的程序冲突。我相信,不是唯一的解决方案,但是可能存在超时问题,网络缓慢问题。

多数情况下,我会说软件不会向您报告正确的错误消息,例如,在java和c#跟踪每个异常的情况下。不要捕获所有异常,而要保留一个可以捕获和记录日志的位置。除非使用远程桌面工具,否则很难解决UI Bug。而且大多数情况下,即使是第三方软件也可能是错误。


-2

如果您使用的是真正的大型应用程序,则可能会有1,000个错误的队列,其中大多数肯定是可重现的。

因此,恐怕我可能会以WORKSFORME(Bugzilla)的身份关闭该错误,然后继续修复一些更明显的错误。或做任何项目经理决定做的事情。

即使进行了局部更改,当然进行随机更改也是一个坏主意,因为您可能会引入新的错误。


我重视诚实。如果没有足够高的优先级来解决,请这样说。不要说它在不起作用时会起作用;那会误导别人。
Technophile
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.