修复错误,还是等待客户找到它们?


35

其他人看到错误时会修复错误,还是等到崩溃/数据丢失/人死后才修复错误?

例子1

 Customer customer = null;
 ...
 customer.Save();

该代码显然是错误的,而且无法解决-在空引用上调用方法。它碰巧不会崩溃,因为Save碰巧不访问任何实例数据;因此就像调用静态函数一样。但是任何地方的任何微小更改都可能突然导致不会崩溃的代码损坏:开始崩溃。

但是,更正代码也是不可想象的:

Customer customer = null;
...
customer = new Customer();
try
   ...
   customer.Save();
   ...
finally
   customer.Free();
end;

可能会导致崩溃;一个没有通过全面测试的单元测试和手动用户测试发现的。

例子2

float speed = 0.5 * ((G * mass1 * mass2) / R) * Pow(time, 2);

认识物理学的人会认识到分母应该是R 2

代码是错误的,这是绝对错误的。高估速度会导致反火箭发射得太早,杀死所有飞船上的人。

但是也有可能过高估计速度掩盖了另一个问题:在航天飞机移动得太快时,安全气囊无法展开。如果我们突然修改了代码:

float speed = 0.5 * ((G * mass1 * mass2) / Pow(R, 2)) * Pow(time, 2);

现在速度是准确的,安全气囊突然在不应该展开的时候展开。

例子3

这是我最近遇到的一个示例,检查字符串是否包含无效字符:

if (StrPos(Address, "PO BOX") >= 0)
{
   //Do something
}

如果事实证明Do something分支中存在错误,该怎么办?修复明显不正确的代码:

if (StrPos("PO BOX", Address) >= 0)
{
   //Do something
}

修复了代码,但引入了一个错误。


我认为它有两种可能性:

  • 修复代码,并因破坏代码而受到指责
  • 等待代码崩溃,并因存在错误而受到指责

什么是政治上怎么办?


示例4-当今的真实错误

我正在构造一个对象,但是调用了错误的构造函数:

Customer customer = new Customer();

事实证明,“无参数”构造函数实际上是继承链中更远的一个参数化构造函数:

public Customer(SomeObjectThatNobodyShouldBeUsingDirectly thingy = null)
public Customer(InjectedDependancy depends)

调用它是一个错误,因为它绕过了所有后续的构造方法。

我可以更改对象的沿袭,以不暴露出如此危险的构造函数,但现在我必须将代码更改为:

Customer customer = new Customer(depends);

但我不能保证此更改不会破坏任何内容。就像上面的示例1一样,也许某人某处在某种神秘的条件下,以某种方式依赖于构造Customer为无效且充满垃圾的构造。

也许Customer现在该对象已正确构造,它可以运行以前从未执行过的代码,现在我可能崩溃。

我不能打赌你妻子的一生。

从现在到星期二,我都可以对其进行测试,我不能对您女儿的生活发誓我没有引入回归。

我要:

  • 修复代码并因破坏代码而受到指责?要么
  • 留下错误,并在客户发现错误时受到指责吗?

33
如果您不愿意更改任何内容(因为可能会破坏某些内容),并且认为自己没有资格查看代码其他部分可能发生的情况,那么您在这里做什么?您是否因为要编写的代码行错误而使键盘瘫痪了?
David Thornley,2010年

3
无疑是一个经过充分研究的问题
穆罕默德·阿尔卡鲁

2
“做某事”通常是对您编写的其他函数或库中函数的调用,无论哪种情况,代码都应该经过单元测试。该过程本身也经过了单元测试,因此当您修复一个非常低的问题时,就有可能引入新的错误...如果我建了一座桥梁,我会首先以较小的规模对其进行测试,而不是让路过桥的人死掉。如果在担心错误时没有进行单元测试,那说明您做错了。无论如何,您都应该责备它,因此,与其进行修复,您可以阻止它,而根本不应该责备它。
塔玛拉·威斯曼

2
“ [等一下],直到人们死了,然后再修复它!” 天哪,我非常希望对此只有一个答案……
克里斯·奈特

3
作为对您所说的一句话的评论:您不知道代码中是否还有其他地方依赖于深奥的行为:是吗?如果有人滥用明显不正确的作用域规则作为其代码中的hack,那么他们的代码是错误的。好的OOP本可以防止该错误,但是您不修复,因为他们使用了不好的做法,使问题更加复杂,使它有可能进一步滥用,并使整个系统变得更加不稳定。修复错误,希望测试能够发现任何问题,如果没有,请修复更多错误。产品的长期稳定性是至关重要的指标。
CodexArcanum 2010年

Answers:


34

这在很大程度上取决于情况,错误,客户和公司。在纠正实现与可能引入新错误之间始终需要权衡取舍。

如果我给出确定该做什么的一般指南,我认为它应该是这样的:

  1. 将缺陷记录在所选的跟踪系统中。如果需要,与管理层/同事讨论。
  2. 如果是可能带来可怕后果的缺陷(例如,您的示例#2),请运行,尖叫,上下跳跃,直到有权限的人注意并确定适当的措施,以减轻与错误修复相关的风险。这可能会推迟您的发布日期,挽救生命,清洗窗户等。
  3. 如果它是不间断的缺陷,或者存在解决方法,请评估修复它的风险是否大于修复的好处。在某些情况下,最好等待客户提出该建议,因为那样的话,您会知道不需要100%不需要花费时间进行修复/重新测试。

请注意,这仅在您即将发布时才适用。如果您处于完全开发模式,则只需记录该缺陷,以便对其进行跟踪,修复并完成。如果要花费超过半个小时的时间来修复和验证,我将去找经理/团队负责人,看看缺陷是否适合当前的发布周期或计划在以后的时间进行。


非常真实 这就是为什么(一些)公司需要技术经理,错误爬网等等:对事物进行优先级排序的原因。我并不是说不要主动-一点也不-但是您必须使用良好的判断力。在错误的时间采取错误的主动行动被称为“大炮”,并可能杀死公司。同样,特定漏洞的重要性因公司而异。对于某些程序,对话框中的错字是一个低优先级的外观错误,将在以后的版本中予以修复,而在其他程序中,则是紧急停机。
鲍勃·墨菲

6
+1以记录缺陷。其他缺陷可能会优先考虑...
2011年

35

客户总是会发现错误。永远不会有来自客户的隐藏错误。最后,您介绍的错误将永远回到您身边。不修复它们只是一种不良的专业做法。专业人士不这样做。

当客户发现错误时,公司看起来很糟糕,而不是单个开发人员。对于公司而言,这要糟糕得多,因此您需要进行更改。如果您真的不确定要进行此更改,以免引入其他错误,请与更高级的开发人员,项目技术负责人或其他可以就此更​​改做出决定并随后处理后果的人员联系。


2
这是一个可悲的事实。我们不得不交付一个经过疯狂测试的项目,但客户仍然设法在3分钟内将其崩溃。
奥利弗·韦勒

4
@Helper方法:也许如果您像理智的人那样对其进行测试,那就更好了。
Vinko Vrsalovic

@Helper方法:虽然,更严重的是,如果真的只有三分钟,这似乎使测试人员不知道客户期望的实际用例是什么。
Vinko Vrsalovic

8
@Helper方法:让参与测试的客户(假设customer == client)。开发人员编写和测试代码的麻烦在于,开发人员无法以相同的方式使用软件。开发人员很温柔。这是他们的工作-他们的艺术:客户像恐慌般的猿猴在上面敲击。在可能的情况下,分担测试工作,分担责任。这并不适合所有环境,但是与客户作为团队而不是顾问合作可以带来更好的软件。
brian chandley,2010年

嗯更糟 (
补白

24

修正错误

我们是这里的专家。如果在代码中找到会导致崩溃或错误行为的失败路径,则需要对其进行修复。根据团队的程序,您可能需要提交缺陷,也许编写回归测试,并在船期的正确时间检入修复程序。如果它是低优先级的错误,那么在里程碑开始附近检入修复程序始终是个好时机,因为如果您确实导致回归,则不会影响里程碑的发布周期。

请勿将其与重构或与性能错误无关的性能改进混为一谈。

分布式源代码管理系统可在其中保留一个“小错误修复”的单独存储库,然后在里程碑的开头轻松合并,这对这里很有帮助。


4
+1。修理它。如果此修复程序破坏了其他功能,那么无论如何也有其他破坏力-也对其进行修复。如果您的测试没有捕获这些中断,则您的测试已损坏-也要解决此问题。您不能因为害怕破坏某些东西而害怕自己更改代码-那条路只会导致彻底的破产。
汤姆·安德森

21

客户会说什么?

这是我想象的结果:

客户:当我做x时,它崩溃了。

程序员:哦,是的!我记得不久前看到过。我认为这没什么大不了的,所以我把它留在那里。

客户: [到达钝器]

是。修复错误。您可以从不断恶化的体验中节省客户,并且可以在紧急情况发生之前对其进行修复。

而且,如果您认为自己的修复程序实际上可能导致崩溃,那么您还没有真正找到修复程序。


8

您提供的所有示例似乎都有一个共同的线索。您似乎想修复一个您不完全了解的错误。我之所以这样说,是因为您注意到了对每个人都有意想不到的后果的可能性。

我可能会说这可能是一个巨大的错误,正如本劳瑞(Ben Laurie)所写的, 并不能修复您不理解的错误。在这个著名的例子中,当Debian团队遵循分析工具的结果时,他们破坏了Debian和Ubuntu等衍生产品的OpenSSL加密。

如果您认为通过查看代码存在缺陷,请确保可以以客户可见的方式重现缺陷。如果不能,为什么不花您的资源来修复其他问题。


7

尽快开始消除您的技术债务

您的示例肯定看起来像是遗留代码,具有很多技术债务,而且我感觉存在对更改的恐惧(顺便说一句,这不是批评或判断)。您的整个团队都必须承认您负有这笔技术债务(因此,不必独自承担责任),然后您可以决定如何处理它。

在示例1中,如果Save()不访问任何实例数据,那么它究竟保存了哪些客户数据?开始修复并测试它。

在示例2中,很容易将速度计算器包含在测试中,并确保在所有关键示例中正确计算出结果。

在示例3中,存在使死代码复活的危险。该代码应该完全消除吗?在这种情况下,布尔条件的意图是什么?是否确保字符串不包含无效字符?还是要确保其中有“ PO BOX”?您越早开始解决这些问题,就越好。

解决了许多此类问题之后,请与您的团队进行某种回顾/验尸。重要的是要从经验中学习,以便将来可以减少缺陷注入率。


5

您已经有了很好的答案。我将添加一些关于担心崩溃的问题的信息。

首先,在理想情况下,软件是模块化的,正确的架构,并且关注点之间存在良好的分离。在这种情况下,您所做的更改几乎不会破坏任何内容,因为您将控制所有相关代码,并且没有任何隐藏的惊喜。

不幸的是,理想的情况是虚构的。无论联接松动的程度如何,都会存在联接,因此有可能破坏其他物体。

解决方案有两个:

  1. 使代码结构合理。
  2. 当代码被隔离得足够使您知道没有其他中断时,请对其进行修复。

通过将整个代码重写为新的体系结构设计,无法使代码结构良好。相反,在测试的指导下进行重构是您的朋友。在此步骤中,您不会更改功能。

第二步是修复该错误。

有几点要注意:

  1. 此过程绝对需要版本控制
  2. 重构步骤和错误修复步骤最好作为单独的提交提交给版本控制,因此每个都有明确定义的历史功能。
  3. 不要着眼于再犯一个错误,您将一事无成。而是考虑使您的代码更好。换句话说,除非您知道要增加错误而不是减少错误,否则应该这样做。
  4. 与最后一点有关:不要试图预测未来。人们偏向于认为自己非常擅长预测。实际上,我们的预测能力是短期的。因此,不必担心将来会出现不确定的错误。这也是YAGNI背后的原则。
  5. 在bug世界中版本控制的相应工具是bug跟踪器。您也将需要它。
  6. 您需要修复错误的原因有两个:为了使客户满意;为了能够在您的发展中取得进步。要使用示例3(物理学上的示例):如果程序用这样一个残缺的方程式满足客户,则该软件的许多其他部分开发错误,以减轻此错误(例如安全气囊部署)。如果此软件需要版本2(或1.1),那么您将发现基于此错误代码开发正确的代码越来越困难。然后,您要么要进行大笔重写,要么要进行大笔失败。两者都应避免。

这些已经超过了几点,所以我想我会在这里停止。


3

您首先需要考虑错误的定义:

  1. 所读取的代码与您认为正确的代码不匹配
  2. 该软件无法正确执行其任务

您似乎专注于#1,而#2是最好的坐姿。当然,我们的程序员希望我们的代码正确无误(#1),但是人们为它的正常运行付费(#2)。

您可能会或可能不会对可能偶然引入新错误的代码库进行的操作与当前软件的#2视图无关。但是,#1对您自己或随后的维护程序员很重要。有时很难决定,但是当#2和#1发生冲突时,您必须知道#2显然更为重要。


2

都不行 第三种方法是:从业务角度寻找一种方法来证明“有问题的代码”实际上是在引起问题。与BA / QA或至少与您的经理一起确认您找到的内容。然后在每个人都知道问题时计划修复程序。

在您提到的情况下,除了有效的错误之外,还有更多可能的方案:

  1. 您正在查看的代码是一些无效代码。可能是因为像ysolik所说:客户总是会发现错误。如果没有,则代码永远不会执行。
  2. 在WTF情况下,明显的错误确实有其目的。(我们正在谈论生产代码,什么都可能发生,对吧?)
  3. 商业/客户已经知道了这个问题,但是没有必要解决。
  4. 也许更多...

在上述任何情况下,如果我是经理,我都不希望开发人员使用他/她的判断来纠正“错误”。在大多数情况下,修复错误可能会有所帮助,但是,如果出错,可能会导致麻烦多于其良好意图。


1
如果您只想雇用不使用自己判断的开发人员,那么有很多真正平庸的开发人员可以为您服务。您将很难聘请对自己的能力有信心的实际优秀人才。
David Thornley 2010年

1
@戴维:不要将我的观点扩展到不适当的程度。开发人员肯定需要他们的判断,但应该有一个界限。在这种情况下,开发人员会根据自己的判断来发现潜在的错误,并采取进一步措施加以解决。
Codism

2

我是否:

  • 修复代码并因破坏代码而受到指责?要么
  • 留下错误,并在客户发现错误时受到指责?

您修复了该错误,开始了单元测试,当它们成功时,您检入了修复程序。

(或者,如果您的单元测试花费了很长时间,则请先签入修复程序,然后等待CI工具是否向您发送邮件,因为您的提交损坏了。)


1
或者,如果您使用门禁检入,请进行设置,这样您实际上就不会检入损坏的代码。
亚当李尔

3
花很长时间并不是提交伪劣代码的借口。
Toby

@Toby:谁在说借口?我目前在一个小团队中工作,甚至没有六个开发人员。该项目的单元测试需要1个小时。我们的政策是运行似乎与您所做的事情相关的测试,然后检入并让CI查找您是否破坏了看似无关的东西。在一个大团队中这是行不通的,但是在一个小团队中,这样可以节省很多时间。
2010年

1

如果它们是崩溃/数据丢失错误,请修复它们。附带已知数据丢失错误的程序是完全恶意的,不可原谅的。

如果该错误是外观错误或非关键错误(可以避免),则应将其记录在案并提供解决方法。理想情况下,应该对其进行修复,但是有时对于当前版本修复它过于昂贵。

请注意,自述文件中每个大型软件项目都有一个“已知问题”部分,该部分通常确切列出以下内容:已知错误。

恕我直言,只知道真正的次要/化妆错误,不知道错误且不进行交流是不可接受的。


1

修复它,并进行测试。如果您决定仅仅因为害怕发现更多错误而决定保留已知错误,则您的程序将成为计时炸弹的地雷区,其速度如此之快,以至于比您想像的更快无法修复。

由于您是主控者,而代码是从属者,因此当您发现错误时,可以不必担心更改它。对代码的恐惧(“可能会通过破坏其他地方来进行报复”)是完全不能接受的。


0

如果明显有崩溃或发生问题,则应进行修复。如果规范中有歧义,即如果您发现自己在想“客户可能会期望这样做,但看起来可能是一个错误”或规范中存在问题,例如“我们被要求这样做”但很糟糕”,那么您需要找出要做什么。把代码扔在墙上,等待客户的反馈很不好-您可能会问产品经理是否有,或者在部署产品之前问客户。

请记住,“我们知道该问题,并将在以后的版本中修复”与“我们知道该问题,但不太关心您来避免您处理它”是同义词。


0

正确的做法既不是忽略错误,也不是当场“修复”该错误。由于您在问题中指出的原因。

我认为,您应该首先理解代码。如果您看到的代码已经存在了一段时间,并且还没有人注意到“ bug”,则可能是有原因的。尝试找到这个原因。这是我在做出决定之前要查看的内容:

  • 历史记录:使用您的版本控制软件来回答以下问题:谁触摸过代码?他们改变了什么?他们用什么提交消息将其签入?您能推断出代码看起来像的原因吗?

  • 使用:哪些代码使用了错误代码?如何?代码死了吗?还有其他依赖错误行为的代码吗?

  • 作者:如果您不能使用上述信息快速得出结论,请询问代码的作者(至少可以这样做),以了解为什么代码看起来如此。通常您会得到一个“糟糕的消息,应该修复!” 或“不!不要更改它!!!!!!马上。

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.