解决已知错误后,其他地方可能会出现新错误的原因是什么?


14

在讨论中,我的一位同事告诉他,在尝试解决错误时,他目前的项目有些困难。他说:“当我解决一个错误时,其他地方就会停止工作。”

我开始考虑如何发生,但无法弄清楚。

  • 当我太累/困得无法正确执行工作并无法全面了解正在处理的代码部分时,有时会遇到类似的问题。在这里,问题似乎持续了几天或几周,与我同事的关注点无关。
  • 我也可以想象这个问题是在一个非常大的项目,一个管理不善的项目中引起的,在这个项目中,队友不知道谁在做什么,而对其他人的工作有什么影响可以改变他们正在做的事情。这里也不是这样:这是一个只有一个开发人员的相当小的项目。
  • 对于旧的,维护不善且从未记录过的代码库,这也可能是一个问题,只有真正能够想象变更后果的开发人员才在几年前离开了公司。在这里,该项目才刚刚开始,开发人员不使用任何人的代码库。

那么,由一个专注于自己的工作的开发人员编写的全新的,小型代码库中的此类问题可能是什么原因呢?

有什么帮助?

  • 单元测试(没有)?
  • 正确的体系结构(我很确定代码库根本没有体系结构,并且编写时没有任何初步思考),需要整个重构吗?
  • 配对编程?
  • 还有吗

14
啊,很好的“级联失败浪潮”设计模式。:-)
Brian Knoblauch

1
我把它比作接触中的气泡。向下推,它在其他地方弹出。我的编码越好,看到的内容就越少
johnc

2
附带一提,我在嵌入式系统上就拥有该功能。我添加了一个函数调用来解决问题。对于堆栈而言,该函数调用太多了(微控制器没有堆栈溢出检测功能),因此它在内存中的其他位置写入了一些随机内容,这当然使某些地方完全不同了。因此,这种事情可以发生在只有一个开发人员和良好架构的小型代码库上。
上升黑暗

...那是调试的噩梦。
上升黑暗

Answers:


38

它与重点,项目规模,文档或其他过程问题无关。诸如此类的问题通常是设计中过度耦合的结果,这使得隔离变更非常困难。


15
这与不良或没有回归测试相结合
Ryathal 2011年

3
是的,@ Ryathal,尽管回归测试不能防止此类错误,但请让您早点了解它们。
Karl Bielefeldt

如果您尽快(例如在创建错误的几分钟之内)了解它们,则可以撤消更改并有效地假装它们从未发生。
bdsl

14

原因之一可能是软件组件之间的紧密耦合:如果组件之间没有简单的,定义明确的接口,则即使对代码的一部分进行很小的更改也会在软件的其他部分引入意外的副作用。码。

例如,最近我正在研究一个在我的应用程序中实现GUI组件的类。数周以来,报告了新的错误,我对其进行了修复,新的错误出现在其他位置。我意识到该类已经变得太大,正在做太多事情,并且许多方法依赖于按正确顺序调用的其他方法才能正常工作。

我没有修复最新的三个错误,而是进行了一些强大的重构:将组件拆分为主类和MVC类(三个附加类)。这样,我不得不将代码拆分为更小,更简单的部分,并定义更清晰的接口。重构后,所有错误均已解决,并且未报告新错误。


7

一个错误掩盖另一个错误很容易。假定错误“ A”导致调用错误的函数来处理输入。修复错误“ A”后,突然调用了未经测试的正确功能。


5

好吧,直接原因是两个错误使一个人正确,或者至少犯了一个显而易见的错误。该代码的一部分补偿了另一部分的不正确行为。或者,如果第一部分不是这样的“错误”,则在更改代码时,这两个部分之间存在一些未成文的约定。

例如,假设函数A和B对某些量使用从零开始的约定,因此它们可以正常工作,但是C使用一个,您可以“修复” A与C一起工作,然后发现B的问题。

更深层的问题是缺少对各个零件正确性的独立验证。单元测试旨在解决此问题。它们还充当适当输入的规范。例如,一组很好的测试将清楚地表明函数A和B期望基于0的输入,而C期望基于1的输入。

根据项目的需要,也可以通过其他方式正确确定规格,从正式文档到代码中的良好注释。关键是要了解每个组件的期望和承诺,以便您可以发现不一致之处。

良好的体系结构有助于解决理解代码的问题,从而使其更容易。配对编程有助于避免或首先发现错误。

希望这可以帮助。


5

紧密耦合,缺乏测试,这些可能是最常见的罪魁祸首。基本上,常见的问题只是伪劣的标准和程序。另一个是不正确的代码,设法通过正确的行为获得幸运。考虑memcpy来自Linus Torvalds的错误,在该错误中更改其实现会暴露(未引起)客户端中的错误,而这些错误本memcpy应用于memmove重叠源和目的地的地方。


4

听起来这些“新”错误实际上不是“新”错误。直到真正解决了其他被破坏的代码,这才不是问题。换句话说,您的同事并没有意识到他一直都在犯两个错误。如果没有被证明被破坏的代码没有被破坏,那么一旦其他方面的代码被实际修复,它也不会失败。

在这两种情况下,更好的自动化测试方案都可能会有所帮助。听起来您的同事需要对当前代码库进行单元测试。将来,回归测试将验证现有代码是否继续起作用。


0

提高自动化测试方案的广度。始终在提交代码更改之前运行全套测试。这样,您将检测到更改的有害影响。


0

我只是在测试不正确时遇到了这个问题。测试检查的给定权限状态为!正确。我更新了代码并运行了权限测试。有效。然后我进行了所有测试。使用已检查资源的所有其他测试均失败。我更正了测试和权限检查,但起初有些恐慌。

规格不一致也会发生。然后,几乎可以肯定,修复一个错误将创建另一个错误(令人兴奋的是,直到该项目的稍后版本才执行该规范的特定部分)。


0

假设您有一个完整的产品。然后,您添加了一些新内容,一切似乎都很好,但是您又破坏了其他内容,这取决于您为了使新功能起作用而需要更改的代码。即使您不更改任何代码,仅向现有功能添加功能,也可能会破坏其他功能。

所以基本上您几乎回答了自己:

  • 松耦合
  • 缺乏测试

只需学习适应TDD原理(至少对于新功能),然后尝试测试可能发生的每种可能状态。

结对编程很棒,但并不总是“可用”(时间,金钱,两者..)。但是,每天/每周/一次提交一次的代码审查(例如,由您的同事进行)也将大有帮助,尤其是当审查包括测试套件时。(我发现很难不向测试套件编写错误……有时候我必须在内部测试测试(健全性检查):))。


0

假设开发人员A编写了一些带有错误的代码。该代码并不完全应该执行该操作,但是有些不同。开发人员B编写的代码完全依赖于A的代码执行指定的操作,而B的代码不起作用。B进行调查,在A的代码中找到错误的行为,然后加以解决。

同时,开发人员C的代码只能正常工作,因为他依赖于A的代码错误行为。A的代码现在是正确的。C的代码停止工作。这意味着在修复代码时,您需要非常仔细地检查谁在使用此代码,以及它们的行为随固定代码的变化而变化。

我遇到另一种情况:在某些情况下,某些代码行为不当,并完全停止了某个功能的工作。因此,我更改了不当行为并使该功能正常工作。不幸的副作用是,整个功能在情况X中存在严重问题,并在整个地方都失败了-这对任何人都是完全未知的,因为情况从未发生过。好吧,那很难。

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.