Language agnostic 修复公共库函数,还是放弃?
假设我有一个函数,其中有一个bug: 伪代码:Language agnostic 修复公共库函数,还是放弃?,language-agnostic,Language Agnostic,假设我有一个函数,其中有一个bug: 伪代码: void Foo(LPVOID o) { //implementation details omitted } 问题是用户传递的null: Object bar = null; ... Foo(bar); 那么函数可能会由于访问冲突而崩溃;但它也可能碰巧工作得很好。错误在于函数应该检查传递null的无效情况,但它从来没有检查过。这从来都不是问题,因为开发者被信任知道他们在做什么 如果我现在将函数更改为: MessageBox(HW
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%正确的代码段并在不修改现有代码的情况下解决更改。当然,这并不总是可能的有两种选择:
- 为错误检查版本指定一个新名称,并弃用旧版本(一个版本之后会让它开始发出警告(编译时,如果可能,运行时,如果必要),两个版本之后会删除它)
- [不总是可能的]将新引入的错误检查放在这样的位置,即只有在未修改的版本崩溃或产生未定义的行为时才会触发。(这样,在编写代码时非常小心的用户不会得到任何令人不快的惊喜。)