修复库代码中的错误,还是放弃它们?

时间:2010-10-04 17:53:35

标签: api language-agnostic

假设我在代码库中有一个函数,其中有一个bug 我在代码库中发现了一个错误:

class Physics
{
    public static Float CalculateDistance(float initialDistance, float initialSpeed, float acceleration, float time)
    {
        //d = d0 + v0t + 1/2*at^2
        return initialDistance + (initialSpeed*time)+ (acceleration*Power(time, 2));
    }
}
  

注意:示例和语言是假设的

我无法保证修复此代码不会破坏某人。

可以想象,有些人依赖于此代码中的错误,修复它可能会导致错误(我无法想到可能发生的实际方法;也许它与它们有关建立距离查找表,或者如果距离错误值而不是他们期望的那样,他们可能只是抛出异常

我应该创建第二个功能:

class Physics
{
    public static Float CalculateDistance2(float initialDistance, float initialSpeed, float acceleration, float time) { ... }

    //Deprecated - do not use. Use CalculateDistance2
    public static Float CalculateDistance(float initialDistance, float initialSpeed, float acceleration, float time) { ... }
}

在没有正式弃用代码的语言中,我是否相信每个人都可以切换到CalculateDistance2

它也很糟糕,因为现在理想命名函数(CalculateDistance)永远会丢失一个可能没有人需要的遗留函数,并且不想使用它。

我应该修复错误,还是放弃它们?

另见

6 个答案:

答案 0 :(得分:3)

您永远不会成功使用您的图书馆迎合每个现有项目。试图这样做可能会产生一种受欢迎的可预测感,但也会导致它变得臃肿和停滞不前。最终,这将使它更容易被更简洁的库替换。

与任何其他项目一样,应该期望经历迭代变更并重新发布。由于您当前的大部分用户都是应该熟悉的程序员,因此改变对他们来说真的不应该让他们感到惊讶。只要您通过版本控制识别版本并记录其间的更改,他们应该知道在更新时会发生什么,即使这意味着他们决定继续使用他们已有的版本。

此外,作为一个可能的新用户,由于公然不愿意修复已知的错误而发现您的图书馆拥有越来越多的遗留代码行,这告诉我项目的可维护性和可持续性都可能很差。

所以,老实说我会说要解决它。

答案 1 :(得分:2)

我曾经用一些MFC代码进行过多次战斗,这些代码的行为完全出乎意料。当我最终发现它在Microsoft提供的库中出错时,我检查了知识库。它被记录为(大约)“这是我们在2个OS版本之前发现的一个已知错误。我们没有修复它,因为有人可能依赖它。”

我有点生气......

我会说你应该弃用它。如果要升级代码所依赖的库,则应使用新库测试代码。如果是遗留代码,则可以使用已知的配置。建议您的用户并继续前进......

答案 2 :(得分:2)

好问题。我期待着其他一些答案。这是我在问题上的2美分:

一般来说,如果你怀疑很多人确实依赖这个bug,那么这就是不修复bug而是创建一个新函数CalculateDistance2的论据。

另一方面,我认为这是更好的选择,不要忘记依赖该错误的人可以继续使用特定的旧版本的库。您仍然可以在发行说明中记录错误的删除(以及修改后的行为或库函数)。

(如果你的类恰好是一个COM组件,传统的观点是创建一个新的接口ICalculateDistance2,使原始接口过时,但保留它以便向后兼容。)

答案 3 :(得分:2)

另一个选择是修复错误,但保留旧代码作为LegacyCalculateDistance方法可用,如果有人真的需要它。

如果您担心为可能无法制作的用户提供兼容性解决方案,您甚至可以实现基于(例如)配置文件或环境变量设置选择“遗留”实现的功能代码级别的更改。

答案 4 :(得分:1)

正如您所描述的那样,这是在满足两个不同用户组之间的权衡:

  • 根据库中的错误构建软件的现有用户
  • 将来将使用您的图书馆的新用户

没有理想的解决方案,我也不认为有一个普遍的答案。我认为这完全取决于有问题的bug和功能。

我想你必须问问自己

“该函数对当前存在的错误有意义吗?”

如果是,请将它留在库中。否则,我可能会把它扔掉。

答案 5 :(得分:1)

仅仅为了争论,让我们假设您的假设语言是C ++(尽管它看起来更像Java)。在这种情况下,我会使用命名空间来创建一个从新旧代码的角度来看(合理)易于处理的分支:

namespace legacy {
class physics { 
    Float CalculateDistance(float initialDistance, float initialSpeed, float acceleration, float time)
    {
    // original code here
    } 
}
}

namespace current { 
class physics {
    Float CalculateDistance(float initialDistance, float initialSpeed, float acceleration, float time)
    {
    // corrected code here
    } 
}

从那里你可以选择两者之间的选择。例如,现有代码可以添加using指令:using legacy::physics;,并且他们将继续使用现有代码而无需进一步修改。新代码可以添加using current::physics;代替,以获取当前代码。当你这样做时,你可能(可能)弃用legacy::physics类,并在一段给定的时间,修订数量等之后安排删除它。这使您的客户有机会检查他们的代码并以有序的方式切换到新代码,同时保持legacy命名空间不会被旧垃圾污染。

如果你真的想详细说明,你甚至可以在命名空间中添加版本编号方案,而不仅仅是legacy::physics,它可能是v2_7::physics。这样就有可能即使你“修复”代码,也可能远程可能仍然存在一两个错误,所以你最终可能会再次修改它,而有些人可能最终会依赖它在它的某些任意版本上,不一定只是原始版本或当前版本。

同时,这限制了用于一个(相当)一小部分代码(或至少是每个模块的一小部分)的版本的“意识”,而不是它遍及所有代码。它还为某人使用新代码编译模块,检查错误,在需要时切换回旧代码等提供了相当轻松的方式,而无需直接处理所讨论的函数的每个单独调用。 / p>