6

我经常有基于特定明确算法的代码。这得到了很好的评论,看起来很合适。对于大多数数据集,该算法效果很好。

但是随后添加了边缘情况、特殊情况、启发式方法来解决特定数据集的特定问题。随着特例越来越多,评论也越来越模糊。我害怕在一年左右的时间里回头查看这段代码,并试图记住为什么要添加每个特定的特殊情况或启发式。

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

处理这种情况的最佳实践是什么?

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

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

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

4

8 回答 8

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);
}

不是一个硬性和快速的具体示例,但它会在一两年内帮助提高可读性。

于 2009-06-05T20:42:07.157 回答
4

单元测试可以在这里提供帮助。拥有实际模拟特殊情况的测试通常可以作为说明代码为何执行此操作的文档。这通常比在评论中描述问题要好。

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

于 2009-06-05T20:48:42.060 回答
2

如果您有项目的知识库或 wiki,您可以在其中添加图表,按照Matthew 的 Fowler 引用的方法链接到它,也可以在边缘案例更改的源代码控制提交消息中链接到它。

//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

这是更多的工作,但是一种比单纯的测试用例或评论更彻底地记录用例的方法。即使有人可能会争辩说测试用例应该是足够的文档,例如,您可能不想将整个失败的数据集存储在其中。

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

于 2009-06-05T20:52:38.133 回答
1

我通常不提倡测试驱动开发和过分强调测试的类似风格,但这似乎是一堆单元测试可以提供很大帮助的完美案例。甚至不是首先从以后的更改中捕获错误,而只是记录所有需要解决的特殊情况。

一些带有注释的好单元测试本身就是对特殊情况的最佳描述。代码本身的注释也变得更容易了。可以简单地指出一些单元测试来说明代码中当时正在解决的问题。

于 2009-06-05T20:52:34.733 回答
1

有关

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

部分:

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

/**
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.
*/
于 2009-06-05T21:12:31.590 回答
1

Don Knuth 发明了文学编程,使您的程序文档可以轻松地包含绘图、图形、图表、数学方程以及任何其他您需要使其理解的内容。一个识字程序是解释为什么某事是这样以及它是如何随着时间的推移变成这样的好方法。有很多很多识字的编程工具;“noweb”工具是最简单的工具之一,它随一些 Linux 发行版一起提供。

于 2009-06-05T22:25:54.780 回答
0

在不了解问题的具体性质的情况下不容易给出答案,但根据我自己的经验,必须避免处理硬代码的特殊情况。你有没有想过实现一个规则引擎或类似的东西来处理你的主要处理算法之外的特殊情况?

于 2009-06-05T20:40:15.430 回答
0

听起来您需要更详尽的文档,而不仅仅是代码注释。这样,某人可以在文档中查找有问题的函数,并看到需要特殊情况的示例图片。

于 2009-06-05T21:04:42.323 回答