13.2 不要重复代码

不幸的是,许多注释并不是特别有用。最常见的原因是注释重复了代码:注释中的所有信息可以很容易地从注释旁边的代码中推导出来。这是最近的一篇研究论文中出现的代码示例:

ptr_copy = get_copy(obj)                 # Get pointer copy 
if is_unlocked(ptr_copy):                # Is obj free?
    return obj                           # return current obj
if is_copy(ptr_copy):                    # Already a copy?
    return obj                           # return obj
thread_id = get_thread_id(ptr_copy) 
if thread_id == ctx.thread_id:           # Locked by current ctx
    return ptr_copy                      # Return copy

这些注释中没有任何有用的信息,除了“Locked by”这个注释以外,因为这个注释暗示了一些从代码中可能看不出来的关于线程的信息。请注意,这些注释的详细程度与代码大致相同:每行代码都有一条注释,用于描述该行。像这样的注释很少有用。

这里有更多重复了代码的注释的例子:

// Add a horizontal scroll bar 
hScrollBar = new JScrollBar(JScrollBar.HORIZONTAL); 
add(hScrollBar, BorderLayout.SOUTH);

// Add a vertical scroll bar 
vScrollBar = new JScrollBar(JScrollBar.VERTICAL); 
add(vScrollBar, BorderLayout.EAST);

// Initialize the caret-position related values 
caretX = 0; 
caretY = 0;
caretMemX = null;

这些注释都没有提供任何价值。对于前两个注释,代码已经足够清晰,并不真的需要注释;在第三种情况下,注释可能是有用的,但当前的注释并没有提供足够的细节以提供帮助。

在你写完注释后,问问自己以下问题:一个从未见过这段代码的人,仅仅通过看注释旁边的代码就能写出这段注释吗?如果答案是肯定的,就像上面的例子一样,那么注释并没有使代码更容易理解。像这样的注释就是有些人认为注释没有价值的原因。

另一个常见的错误是在注释中使用与被注释的实体名称中出现的相同的词:

/* 
 * Obtain a normalized resource name from REQ.
 */ 
private static String[] getNormalizedResourceNames(
       HTTPRequest req) ...

/* 
 * Downcast PARAMETER to TYPE.
 */ 
private static Object downCastParameter(String parameter, String type) 
         ...

/* 
 * The horizontal padding of each line in the text. 
 */ 
private static final int textHorizontalPadding = 4;

这些注释只是从方法或变量名称中抽取一些词,也许再加上一些参数名称和类型的词,然后把它们组成一个句子。例如,第二个注释中唯一没有在代码中出现的是“to”这个词!再一次,这些注释只通过看声明就能够写出来,不需要了解变量的方法;结果,它们没有任何价值。

危险信号:注释重复了代码

同时,注释中缺少一些重要的信息:例如,什么是“规范化的资源名称(normalized resource name)”,getNormalizedResourceNames返回的数组中的元素是什么?“downcast”是什么意思?填充的单位是什么,填充是在每行的一边还是两边?在注释中描述这些东西会很有帮助。

写好注释的第一步是在注释中使用与被描述的实体名称中不同的词。为注释挑选那些提供关于实体含义的额外信息的词,而不是仅仅重复它的名称。例如,下面是对textHorizontalPadding的一个更好的注释:

/* 
 * The amount of blank space to leave on the left and 
 * right sides of each line of text, in pixels.
 */ 
 private static final int textHorizontalPadding = 4;

这个注释提供了从声明本身看不出的额外信息,比如单位(像素)和填充适用于每一行的两端的事实。该注释没有使用“填充(padding)”这个术语,而是解释了什么是填充,以防读者还不熟悉这个术语。

Last updated