it-swarm.cn

注释掉的代码真的总是不好吗?

实际上,我读过的每篇关于代码质量的文章都同意注释掉代码是一件坏事。通常的示例是,有人更改了一行代码,并将旧行留在此处作为注释,这显然使以后阅读该代码的人感到困惑。当然,这是一件坏事。

但是我经常发现自己在另一种情况下会留下注释掉的代码:我编写了一种计算几何或图像处理算法。要了解此类代码并查找其中的潜在错误,显示中间结果通常非常有帮助(例如,在屏幕上绘制一组点或保存位图文件)。在调试器中查看这些值通常意味着查看一堵数字墙(坐标,原始像素值)。不是很有帮助。每次编写调试器可视化程序都是过大的。我不想将可视化代码留在最终产品中(这会损害性能,并且通常只会使最终用户感到困惑),但是我也不想失去它。在C++中,我可以使用#ifdef来有条件地编译该代码,但是我发现两者之间没有太大区别:

/* // Debug Visualization: draw set of found interest points
for (int i=0; i<count; i++)
    DrawBox(pts[i].X, pts[i].Y, 5,5);
*/

和这个:

#ifdef DEBUG_VISUALIZATION_DRAW_INTEREST_POINTS
for (int i=0; i<count; i++)
    DrawBox(pts[i].X, pts[i].Y, 5,5);
#endif

因此,在大多数情况下,我只是将可视化代码保留为注释,而注释则说明正在可视化的内容。一年后,当我阅读代码时,通常我很高兴我可以取消注释可视化代码,而从字面上“看看发生了什么”。

我应该为此感到难过吗?为什么?有更好的解决方案吗?

更新:S. Lott发表评论

您是否以某种方式“过度概括”了所有已注释的代码,以包括调试以及毫无意义的过时代码?您为什么得出这个过于笼统的结论?

我最近读过罗伯特·马丁斯(Robert Martins)的“清洁代码”,其中说:

很少有实践像注释代码那样令人讨厌。不要这样做!.

我再次查看了本书中的段落(第68页),没有限定,没有区别注释代码的不同原因。所以我想知道这条规则是否过于笼统(或者我是否对这本书有误解),或者我做的是不好的做法,出于某种原因,我不知道。

53
nikie

与将其注释掉相比,#ifdef的好处是(在大型项目上)您可以在make或config文件中列出定义-因此不必手动删除注释,构建然后重新生成-在很多地方给他们加注释。不利的一面是,更改项目的DEFINE通常将意味着重新编译整个内容,而不仅仅是更改文件。

虽然...我认为“注释掉的代码是一件坏事”,实际上是指死代码人们只是出于某种原因不想删除(害怕丢掉他们已经花费的东西)时间也许?)。这实际上与您要寻求的情况无关。

58
TZHX

如果将其注释掉,则可能会腐烂:当您突然决定再次需要它时,您意识到它不再可以编译,或者需要重写以使其与与此同时发生变化的其他事物相适应。

如果将代码保留在其中,但是如果不需要的话,编译器可以对其进行优化,那么您将受益于保持代码为最新and不必承受添加的二进制代码大小或运行时性能。

例如,在C中,这有腐烂的危险:

/*
doSomeDebugStuff();
*/

这也是:

#if 0
doSomeDebugStuff();
#endif

但这很好,因为它始终由编译器检查有效性,但可能会被优化:

if (0)
{
  doSomeDebugStuff();
}

编辑:正如其他人指出的那样,使用有意义的符号而不是0的测试甚至更好。

25
Graham Borland
// The problem with commented out code is that it can hide what you're actually
// trying to say in a wall of text.  Syntax highlighting may help, but you're 
// still left with this huge ginormous wall of text in front of you, searching
// through it for what the actual answer is. You'd think that mentally it'd be 
// really easy to disregard the comments, but in actual usage, it's a lot harder
// than a one Word answer that can tell you what you're looking for. It's tough.
/* Sometimes they'll even through you off with different comments. */ Yes.
// It's really tough to deal with people that don't like to use source control, 
// that would rather comment lines and lines of code instead of deleting the 
// code and checking in revision.  Cue irrelevant paragraph about the reason why 
// I wrote this instead of just deleting the entire block and replacing it 
// with my intention. Maybe I was hedging my bets? Cue misspelled wrod.  
18
George Stocker

我认为有必要区分已过时的注释掉的代码和仅用于调试版本(或有条件地编译到的另一个“特殊”版本)中的代码。后者是一种常见的做法,没有错。

前者不应出现在源代码库中,因为如果您想找回它,版本控制系统将跟踪过时的内容。

15
Alex Budovski

编码中几乎没有“总是” :)如果您对准则背后的原因有足够的了解,并且确实有违反准则的充分理由,请这样做。

例如,当我执行“ kamikaze-refactoring”时,我将代码注释掉,并且需要视觉提示以将其添加回去,或者记住旧代码在一段时间内是如何工作的。在这样的实例中,至关重要的是您稍后将删除注释,但否则它们只会使您的代码混乱。

11
Homde

有时您将代码放在注释中以显示如何使用一个类-这与以前运行的注释掉代码有很大不同。

8
Ian

我进行了大量代码审查,发现无论出于何种原因,注释的代码都没有真正的借口。如果将注释的代码用于调试目的,则可以创建在发布模式下禁用的跟踪机制或具有跟踪级别的跟踪机制(总是可以在发行版中进行跟踪),或者可以仅使用调试器。

带注释的代码是不好的,因为当其他人阅读该代码时(尤其是当您在原作者休假时被迫尝试修复错误时)尤其是在阅读该代码时会感到非常困惑,尤其是如果错误是由于错误地导致的。放在//行的开头...即使使用/ *,您也可能无意中注释了应该在其中的内容-或没有。

为了使您的代码保持清洁和可读性,请删除已注释的代码,因为它本身很难读取程序,而不必读取可能重要的代码。

3
AndersK

是的。

即使您有生产版本中不需要的调试代码,也不应将其注释掉。使用#ifdef更好,因为这样您就可以使用#define宏或通过单独的构建配置轻松地打开和关闭调试。绝对不必手动进入代码并手动注释/取消注释调试代码的每个块。

并且,如果需要灵活地打开某些调试块,而不必打开其他调试块,则应将调试块分组为“调试级别”。

更好的解决方案是根本不使用预处理器,而使用本机语言功能,例如常量和if语句。所以代替

#define DEBUG0
#ifdef DEBUG0
  // debugging code
#endif

你可以有

const bool DEBUG0 = true;
if(DEBUG0)
{
  // debugging code
}

与使用预处理器相比,这样做的好处是,调试代码将始终由编译器检查。当您更改周围的代码时,这会降低其腐烂的可能性。

如果将boolean标志设为false,则不会对性能造成任何影响,因为现代编译器会优化无法访问的代码。最糟糕的是,您可能会收到编译器警告。

2
Dima

我不认为您所做的事情很糟糕,但我认为至少您应该有一些实际注释来解释它在做什么,为什么以及如何以及何时使用它。

我个人通常将这种事情放在有关代码的IF DebugMode = TRUE类型工作中,并将其设置为命令行/启动参数。对我来说,这很容易看到这就是为什么存在代码以及如何设置代码的原因,尽管在您的实例中可能存在性能问题,即使您希望避免进行较小的比较。

因此,我可能会将您正在做的事情视为必要的罪恶,而不是一劳永逸的错误。如果您可以找到某种方法来简化它,那么显然可以这样做,但是我不会为此而烦恼。

1
Jon Hopkins

我认为注释掉代码被认为是代码异味的原因之一是,它表明将其放入代码中的程序员不了解其源代码控制或未使用任何源代码。这两种方式中的任何一种都对他们也正在做的许多其他事情产生了进一步的怀疑。

如果您有合理的理由and,请说明为什么可以找到它是合理的理由,您可能做得很好。通常被认为是坏消息的大多数事情在正确的地方也可能是有用的工具。问题在于那些手比认为自己有手的人稀有。

0
glenatron

它有助于提供有关程序员当时的思维方式的历史记录。但是,在当今无处不在的源代码控制时代,没有理由将其保留下来-以前的版本将包含较旧的代码(如果您需要引用它的话)。

0
5arx

我认为这里没有绝对值。如果只是一个小片段,有时我会留下注释掉的代码,尤其是,如果我有合理的机会很快再次取消注释的话。基本上,只要不影响实际代码的可读性,并且不至于无处不在,我就保留这些代码段。

我绝对拒绝的是注释掉代码的完整方法。是的,我之前见过:WTF。他们可以在源代码修订天堂休息;-)

0
Andres F.