如何管理特殊情况和启发式

时间:2009-06-05 20:36:00

标签: c++ c literate-programming

我经常使用基于特定定义算法的代码。这得到了很好的评论,似乎是正确的。对于大多数数据集,算法运行良好。

然后边缘情况,特殊情况,启发式方法被添加以解决特定数据集的特定问题。随着特殊情况的数量增加,评论越来越模糊。我担心在一年左右的时间内回过头来查看这段代码并试图记住为什么会添加每个特殊的特殊情况或启发式。

我有时希望有一种方法可以在源代码中嵌入或链接图形,所以我可以有效地说,“在这个数据集的图形中,这个特殊功能导致例程触发不正确,所以这就是为什么这段代码添加了“。

处理此类情况的最佳做法是什么?

似乎总是需要特殊情况来处理这些异常/边缘情况。如何管理它们以使代码保持相对可读性和可理解性?

考虑一个处理照片特征识别的例子(不完全是我正在研究的,但这个比喻似乎很合适)。当我找到一般算法失败的特定图片并且需要特殊情况时,我会在评论中尽可能地记录该信息(或者如下面建议的某个描述性函数名称)。但是经常缺少的是指向展示相关行为的特定数据文件的永久链接。虽然我的评论应该描述这个问题,并且可能会说“请参阅文件foo.jp以获取此行为的示例”,但此文件永远不会出现在源代码树中,并且很容易丢失。

在这种情况下,人们会将数据文件添加到源树中以供参考吗?

8 个答案:

答案 0 :(得分:6)

Martin Fowler在他的重构书中说,当你觉得需要在你的代码中添加注释时,首先要看看你是否可以将该代码封装到一个方法中,并为该方法命名,以取代注释。

因此,您可以创建一个名为。

的方法
private bool ConditionXAndYHaveOccurred(object param)
{
   // code to check for conditions x and y
   return result;
}

private object ApplySolutionForEdgeCaseWhenXAndYHappen(object param)
{
   //modify param to solve for edge case
   return param;
}

然后你可以编写像

这样的代码
if(ConditionXAndYHaveOccurred(myObject))
{
    myObject = ApplySolutionForEdgeCaseWhenXAndYHappen(myObject);
}

这不是一个坚定而快速的具体例子,但它有助于在一两年内实现可读性。

答案 1 :(得分:4)

单元测试可以在这里提供帮助。实际模拟特殊情况的测试通常可以作为代码执行操作的原因的文档。这通常比仅仅在评论中描述问题更好。

并不是说这取代了将特殊情况处理移到他们自己的功能和体面的评论......

答案 2 :(得分:2)

如果您有项目的知识库或wiki,您可以在其中添加图表,按照Matthew's Fowler quot e在方法中链接到该图表,也可以在边缘案例的源代码管理提交消息中链接到该图表更改。

//See description at KB#2312
private object SolveXAndYEdgeCase(object param)
{
   //modify param to solve for edge case
   return param;
}

Commit Message: Solution for X and Y edge case, see description at KB#2312

这是更多的工作,但是比单纯的测试用例或评论更彻底地记录案例的方法可以。尽管有人可能会认为测试用例应该是足够的文档,但您可能不希望将整个失败的数据集存储在其中。例如。

请记住,模糊的问题会导致模糊的解决方案。

答案 3 :(得分:1)

我通常不是测试驱动开发和类似风格的倡导者,他们过于强调测试,但这似乎是一个完美的案例,其中一堆单元测试可以帮助很多。甚至不是首先从后来的变化中捕获错误,而只是记录所有需要解决的特殊情况。

一些好的单元测试及其中的注释本身就是特殊情况的最佳描述。而且代码本身的评论也变得更容易了。可以简单地指出一些单元测试,它们说明了代码中此时正在解决的问题。

答案 4 :(得分:1)

关于

  

我有时希望有一种方法可以在源代码中嵌入或链接图形,   所以我可以有效地说,“在这个数据集的图表中,这个特别   这里的功能导致例程错误地触发,这就是为什么这一部分   代码已添加“。

部分:

如果要嵌入的“图形”是图表,并且使用Doxygen,则可以在评论中嵌入dot命令以在文档中生成图表:

/**
If we have a subgraph looking like this:
\dot
digraph g{
A->B;
A->C;
B->C;
}
\enddot
the usual method does not work well and we use this heuristic instead.
*/

答案 5 :(得分:1)

Don Knuth发明了literate programming,使您的程序文档可以轻松地包含图表,图形,图表,数学方程式以及其他任何您需要理解的内容。一个有文化的程序是一个很好的方式来解释为什么它是这样的,以及它是如何随着时间的推移而得到的。有许多很多文字编程工具; “noweb”工具是最简单的工具之一,随附一些Linux发行版。

答案 6 :(得分:0)

不知道问题的具体性质并不容易给出答案,但根据我自己的经验,必须避免处理硬编码的特殊情况。您是否考虑过在主处理算法之外处理特殊情况时实施规则引擎或类似的东西?

答案 7 :(得分:0)

听起来您需要比代码注释更全面的文档。这样,有人可以在文档中查找有问题的功能,并提供需要特殊情况的示例图片。