想象一下,我有一个带有错误的函数:
伪码:
void Foo(LPVOID o)
{
//implementation details omitted
}
问题是用户通过了null
:
Object bar = null;
...
Foo(bar);
然后,由于访问冲突,函数可能崩溃;但它也可能正常工作。错误是函数 应该检查传递null
的无效情况,但它从未这样做过。从来没有问题,因为开发人员可以信任他们正在做什么。
如果我现在将功能更改为:
的伪代码:
void Foo(LPVOID o)
{
if (o == null) throw new EArgumentNullException("o");
//implementation details omitted
}
然后那些幸福地使用该功能并且碰巧但没有获得访问冲突的人现在突然开始看到EArgumentNullException
。
我是否继续让人们不正确地使用该功能,并创建该功能的新版本?或者我是否修复了该函数以包含它原本应该包含的内容?
考虑一个常见的错误,微软必须为开发人员修复它:
MessageBox(GetDesktopWindow, ...);
您永远不会永远想要针对桌面制作窗口模型。你将锁定系统。您是否继续让开发人员锁定用户的计算机?或者您将功能更改为:
MessageBox(HWND hWndParent, ...)
{
if (hWndParent == GetDesktopWindow)
throw new Exception("hWndParent cannot be the desktop window. Use NULL instead.");
...
}
实际上,Microsoft将Window Manager更改为自动修复错误参数:
MessageBox(HWND hWndParent, ...)
{
if (hWndParent == GetDesktopWindow)
hWndParent = 0;
...
}
在我的编写示例中,没有办法修补该功能 - 如果我没有给出一个对象,我就无法做我需要做的事情。
您是否有可能通过添加参数验证来破坏现有代码?您是否让现有代码继续出错,结果不正确?
答案 0 :(得分:2)
问题是你不仅要修复bug,而且还要通过引入错误案例来改变方法的语义签名。
从软件工程的角度来看,我主张你尝试尽可能最好地指定方法(例如使用前置条件和后置条件)但是一旦方法出现,规范变化是不可行的(或至少你必须检查所有出现的方法)并且新方法会更好。
答案 1 :(得分:1)
我会保留旧功能,只需让它创建一个警告,通知您每次(可能)错误的使用,然后我会踢开使用它的开发人员,直到他正确使用它。
你无法抓住一切。如果有人写了“MakeLocation(”Ian Boyd“,”是愚蠢的“),该怎么办?”你会创建一个新函数或更改函数来捕获它吗?不,你会解雇开发人员(或者至少惩罚他)。
当然,这需要您记录您的功能所需的作为输入。
答案 2 :(得分:0)
这是自动化测试[单元测试,集成测试,自动功能测试]非常好的地方,它们使您能够通过配置来更改现有代码。
当进行这样的更改时,我会建议找到所有用法,并确保他们表现出你应该如何相信。
我自己会对现有功能进行错误修复,而不是99%的时间都会复制它们。如果它改变了很多行为并且对这个函数有很多调用,你需要非常确定你的变化。
继续进行更改,运行单元测试,然后进行自动功能测试。修复任何错误和你的黄金!
答案 3 :(得分:0)
如果您的代码中有错误,则应该在报告任何错误时执行您通常执行的操作。其中一部分是评估固定和不固定的影响。有时候做错误的正确方法是不修复它,因为它暴露的行为已被接受。有时修复它的成本,或在正常发布周期之外释放修复的图标,会阻止你释放固定的bug一段时间。这不是道德困境,而是成本和收益的经济问题。如果您对发布的代码中存在已知错误感到不安,请发布 known-bugs 列表。
一个选项似乎没有其他受访者建议将错误功能包装在另一个强制您需要的新行为的函数中。在函数可以运行到多行的世界中,有时不太可能引入新的错误来保留99%正确的代码并在不修改现有代码的情况下解决更改。当然,这并不总是可行的
答案 4 :(得分:0)
两种选择:
答案 5 :(得分:0)
这完全取决于您,您的代码库和您的用户。
如果您是Microsoft,并且您的API中存在一个由全球数百万开发人员使用的错误,那么您可能只想创建一个新功能并更新旧功能上的文档。如果可以,您还需要更新编译器以发出警告。 (虽然即便如此,您也许可以更改现有系统;记住,当MS将VC切换到C ++标准时,您必须更新所有#include iostream
并添加using std
以简化现有系统控制台应用程序再次运行?)
它主要取决于功能是什么。如果它是基本的,会产生巨大的连锁反应,那么它可能会破坏很多代码。如果它只是一个辅助功能,那么你也可以解决它。当然,如果你是微软,你的其他代码依赖于你的一个函数中的错误,那么你可能应该修复它,因为这只是让人感到尴尬。如果其他开发人员依赖于该错误(您创建),那么您可能有义务让用户不要破坏他们导致错误的代码。
如果您是小公司或独立开发人员,那么请确保继续并修复该功能。如果您只需要更新自己或少数人使用新的用法,那么修复它是最好的解决方案,特别是因为它甚至不是什么大问题,因为它真正需要的是对该函数的文档的附加说明。例如do not pass NULL
或an exception is thrown if hWnd is the desktop
等
作为一种妥协的另一种选择是创建包装函数。您可以创建一个小的内联函数来检查args然后调用现有函数。这样你在短期内就不需要做太多事情,并且最终当人们搬到新的那个时,你可以弃用甚至删除旧的,在检查之间将代码移动到新的一次。
在大多数情况下,最好修复一个错误的函数,特别是如果你只是添加参数检查而不是完全改变函数的行为。仅仅因为它会破坏一些现有的代码(特别是如果代码是免费的!),这不是一个好主意 - 阅读鼓励 - 糟糕的编码。想一想:如果有人正在创建一个新程序,那么他们可以做得对从一开始,而不是依赖于一个bug。如果他们正在重新编译依赖于bug的旧程序,那么他们只需更新代码即可。同样,它取决于代码是多么混乱和错综复杂,有多少人受到影响,以及他们是否付钱给你,但是必须更新旧代码以便例如初始化那些没有的变量,或者检查错误代码等。
总而言之,在您的具体示例中(根据提供的信息),您应该修复它。