Language agnostic 修复公共库函数,还是放弃?

Language agnostic 修复公共库函数,还是放弃?,language-agnostic,Language Agnostic,假设我有一个函数,其中有一个bug: 伪代码: void Foo(LPVOID o) { //implementation details omitted } 问题是用户传递的null: Object bar = null; ... Foo(bar); 那么函数可能会由于访问冲突而崩溃;但它也可能碰巧工作得很好。错误在于函数应该检查传递null的无效情况,但它从来没有检查过。这从来都不是问题,因为开发者被信任知道他们在做什么 如果我现在将函数更改为: MessageBox(HW

假设我有一个函数,其中有一个bug:

伪代码:

void Foo(LPVOID o)
{ 
   //implementation details omitted
}
问题是用户传递的
null

Object bar = null;

...

Foo(bar);
那么函数可能会由于访问冲突而崩溃;但它也可能碰巧工作得很好。错误在于函数应该检查传递
null
的无效情况,但它从来没有检查过。这从来都不是问题,因为开发者被信任知道他们在做什么

如果我现在将函数更改为:

 MessageBox(HWND hWndParent, ...)
 {
    if (hWndParent == GetDesktopWindow)
       throw new Exception("hWndParent cannot be the desktop window. Use NULL instead.");

    ...
 }
伪代码:

void Foo(LPVOID o)
{
   if (o == null) throw new EArgumentNullException("o");

   //implementation details omitted
}
然后,那些愉快地使用该函数的人,碰巧遇到了访问冲突,但没有遇到,现在突然会看到
EArgumentNullException

我是否继续让人们不正确地使用该函数,并创建该函数的新版本?或者我要修复函数以包含它原本应该具有的功能


现在是道德难题。您是否曾经在现有代码中添加新的健全性检查、安全性检查和断言?或者您是否将旧函数称为已放弃,并使用新函数


考虑一个非常常见的bug,Microsoft不得不为开发人员修复它:

 MessageBox(GetDesktopWindow, ...);
你从来都不想在桌面上做一个窗口模型。你会锁定系统的。您是否继续让开发人员锁定用户的计算机?或者您是否将功能更改为:

 MessageBox(HWND hWndParent, ...)
 {
    if (hWndParent == GetDesktopWindow)
       throw new Exception("hWndParent cannot be the desktop window. Use NULL instead.");

    ...
 }
实际上,Microsoft将窗口管理器更改为自动修复错误参数:

 MessageBox(HWND hWndParent, ...)
 {
    if (hWndParent == GetDesktopWindow)
       hWndParent = 0;

    ...
 }
在我虚构的例子中,没有办法修补函数-如果没有给我一个对象,我就不能在它上做我需要做的事情


通过添加参数验证是否有破坏现有代码的风险?您是否让现有代码继续出错,从而得到错误的结果?

问题在于,您不仅在修复错误,而且还通过引入错误案例来更改方法的语义签名


从软件工程的角度来看,我建议您尽可能最好地指定方法(例如使用前置和后置条件),但一旦方法出现,规范更改是不可能的(或者至少您必须检查所有出现的方法)一种新的方法会更好。

这就是拥有自动化测试(单元测试、集成测试、自动化功能测试)的伟大之处,它们使您能够通过确认更改现有代码

当进行这样的更改时,我建议找到所有用法,并确保它们的行为符合您的想法

我自己会对现有功能进行bug修复,而不是99%的时间重复它们。如果它改变了很多行为,并且有很多对这个函数的调用,你需要非常确定你的改变


因此,继续进行更改,运行单元测试,然后运行自动化功能测试。修正任何错误和错误

我会保留旧函数,让它创建一个警告,通知您每一次(可能)错误的使用,然后我会踢错误使用它的开发人员,直到他正确使用它

你不可能抓住一切。如果有人写了“MakeLocation”(“伊恩·博伊德”,“很蠢”);”?您是创建一个新函数还是更改函数来捕获它?不,你会解雇开发者(或者至少惩罚他)


当然,这需要您记录您的函数作为输入所需的内容。

如果您的代码中有bug,您应该按照报告bug时通常所做的操作。其中一部分是评估修复和不修复的影响。有时,处理bug的正确方法是不修复它,因为它暴露的行为已经被接受。有时候,修复它的成本,或者在正常发布周期之外发布修复的方便性,会让您暂时停止发布修复的bug。这不是道德困境,而是成本与收益的经济问题。如果您一想到发布的代码中存在已知的bug就感到不安,请发布一个已知bug列表

其他受访者似乎都没有建议的一个选项是将buggy函数包装到另一个函数中,该函数会强制实施您所需的新行为。在函数可以运行到多行的世界中,有时不太可能引入新的bug来保留99%正确的代码段并在不修改现有代码的情况下解决更改。当然,这并不总是可能的

有两种选择:

  • 为错误检查版本指定一个新名称,并弃用旧版本(一个版本之后会让它开始发出警告(编译时,如果可能,运行时,如果必要),两个版本之后会删除它)
  • [不总是可能的]将新引入的错误检查放在这样的位置,即只有在未修改的版本崩溃或产生未定义的行为时才会触发。(这样,在编写代码时非常小心的用户不会得到任何令人不快的惊喜。)

这完全取决于您、您的代码库和您的用户

如果您是Microsoft,并且您的API中有一个bug,世界各地数百万开发人员都在使用它,那么您可能只想创建一个新函数,并在旧函数的基础上更新文档。如果可以,还需要更新编译器以提供警告。(即使那时你也可以改变现有的系统,记住当MS切换到VC的C++标准,你必须更新所有的< <代码>包括IOSROWSS和添加<代码>使用STD< /Cult> s来获得简单的现有控制台应用程序工作吗?) 这基本上取决于函数是什么。如果它是一些基本的东西,会产生巨大的涟漪效应,那么它可能会破坏很多代码。如果它只是一个辅助功能,那么您也可以修复它。当然,如果您是Microsoft,而您的其他代码依赖于某个函数中的错误,那么您可能应该修复它,因为这只是普通的emba