乐者为王

Do one thing, and do it well.

编写无需注释的代码

英文原文:https://blog.codinghorror.com/coding-without-comments/

如果代码中充满大量注释是好的话,那么在代码中有无数的注释必定是更好的,真的是这样吗?那可未必。过度是好注释变坏的一种方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
'*************************************************
' Name: CopyString
'
' Purpose: This routine copies a string from the source
' string (source) to the target string (target).
'
' Algorithm: It gets the length of "source" and then copies each
' character, one at a time, into "target". It uses
' the loop index as an array index into both "source"
' and "target" and increments the loop/array index
' after each character is copied.
'
' Inputs: input The string to be copied
'
' Outputs: output The string to receive the copy of "input"
'
' Interface Assumptions: None
'
' Modification History: None
'
' Author: Dwight K. Coder
' Date Created: 10/1/04
' Phone: (555) 222-2255
' SSN: 111-22-3333
' Eye Color: Green
' Maiden Name: None
' Blood Type: AB-
' Mother's Maiden Name: None
' Favorite Car: Pontiac Aztek
' Personalized License Plate: "Tek-ie"
'*************************************************

我经常遇到注释来自那些开发者,他们似乎没有意识到代码已经告诉我们它是如何工作的;我们需要注释告诉我们它为什么这样工作。代码注释被如此广泛地误解和滥用,你可能会发现自己根本不知道它们是否值得使用。注意你需要的东西。下面是没有任何注释的代码:

1
2
3
4
5
r = n / 2;
while ( abs( r - (n/r) ) > t ) {
  r = 0.5 * ( r + (n/r) );
}
System.out.println( "r = " + r );

知道这段代码做什么吗?它是完全可读的,但它到底做什么?

让我们添加一段注释。

1
2
3
4
5
6
// square root of n with Newton-Raphson approximation
r = n / 2;
while ( abs( r - (n/r) ) > t ) {
  r = 0.5 * ( r + (n/r) );
}
System.out.println( "r = " + r );

这应该就是我想要的,真的是这样吗?这是在完全没有注释和每隔一行代码就有精心格式化的史诗般的注释两个极端之间某种满意的、中间道路的妥协?

不全是。与其添加一段注释,我会重构成这样:

1
2
3
4
5
6
7
8
private double SquareRootApproximation(n) {
  r = n / 2;
  while ( abs( r - (n/r) ) > t ) {
    r = 0.5 * ( r + (n/r) );
  }
  return r;
}
System.out.println( "r = " + SquareRootApproximation(r) );

我没有添加任何注释,然而这段神秘的代码现在是完全可以理解的。

尽管注释本身没有好坏,它们却常常被用作代码的支撑。你应该总是写你的代码就跟注释不存在一样。这会迫使你以你能在人力所及的范围想出最简单、最直白、最自文档化的方式写你的代码。

当你重写、重构和重新架构你的代码多次以使你的开发者同事容易阅读和理解时——当你想象不到任何可能的方式你的代码可以被修改而变得更直接和明显时——那时,也只有在那时,你才不得不添加注释解释你的代码做什么。

正如Steve指出的,这是初级和高级开发者之间的一个关键区别:

在过去,一下子看太多的代码老实说超过了我的接受能力,当我不得不处理它时我通常会试图重写它或者至少添加大量的注释。然而今天,我只是艰难地通过它没有抱怨(太多)。当我脑中有个明确的目标和一段复杂的代码要去写的时候,我花费时间去实现它而不是给自己讲述关于它的故事[在注释里]。

初级开发者依赖注释去讲述故事,当他们应该依赖代码去讲述故事的时候。代码是叙述旁白,它们有其自身的价值,但并不意味着替换(故事里的)情节、人物刻画和背景。

或许这就代码注释不可告人的小秘密:写出好的注释你必须是个好作者。注释不是用于编译器的代码,它们是用来和其他人交流想法的言语。虽然我确实要赞美我的程序员同事,但我不能说和其他人有效沟通正是我们的强项。我看过来自我团队中开发者的三段电子邮件,几乎融化了我的大脑。这些是我们信任的人在我们的代码中写的清晰的、可以理解的注释?我以为我们中的一些人可能会更好地坚持我们的优势——也就是说,为编译器写代码,以尽可能清晰的方式,而把注释仅作为最后采取的手段。

写出好的、有意义的注释是困难的。它和写代码本身一样是门艺术,甚至可能更艺术些。正如Sammy Larbi在注释代码的常见借口里说的,如果你觉得你的代码太过复杂以致没有注释就不能理解,那么你的代码可能只是坏的。重写它直到它不再需要注释。如果经过这些努力后,你仍然觉得注释是必要的,那么务必添加注释。越谨慎越好。

Comments