16.4. 维护注释:避免重复

保持注释最新的第二种技术是避免重复。如果文档重复,那么开发人员将很难找到并更新所有相关副本。相反,请尝试仅一次记录每个设计决策。如果代码中有多个地方受某个特定决定的影响,请不要在所有这些地方重复文档。相反,找到放置文档最明显的位置。例如,假设存在与变量相关的棘手行为,这会影响使用变量的几个不同位置。您可以在变量声明旁边的注释中记录该行为。这是很自然的地方,开发人员可能会检查他们是否在理解使用该变量的代码时遇到麻烦。

如果没有一个“明显的”地方来放置特定的文档,开发人员可以找到它,那么创建一个 designNotes 文件,如 13.7. 跨模块设计决策 所述。或者,选择最好的地方,把文档放在那里。另外,在引用中心位置的其他地方添加简短的注释:“查看 xyz 中的注释以了解下面代码的解释。“如果引用因为主注释被移动或删除而变得过时,这种不一致性将是不言而喻的,因为开发人员将无法在指定的位置找到注释;他们可以使用修订控制历史记录来查找注释发生了什么,然后更新引用。相反,如果文档是重复的,并且一些副本没有得到更新,那么开发人员就不会知道他们使用的是陈旧的信息。

不要在另一个模块中记录一个模块的设计决策。例如,不要在方法调用前添加注释,以解释被调用方法中发生的情况。如果读者想知道,他们应该查看该方法的接口注释。好的开发工具通常会自动提供此信息,例如,如果您选择了方法的名称或将鼠标悬停在该方法的名称上,则将显示该方法的接口注释。尝试使开发人员容易找到合适的文档,但是不要重复文档。

如果信息已经在程序之外的某个地方记录了,不要在程序内部重复记录;只需参考外部文档。例如,如果您编写一个实现 HTTP 协议的类,那么就不需要在代码中描述 HTTP 协议。在网上已经有很多关于这个文档的来源;只需在您的代码中添加一个简短的注释,并为其中一个源添加一个 URL。另一个例子是已经在用户手册中记录的特性。假设您正在编写一个实现命令集合的程序,其中有一个负责实现每个命令的方法。如果有描述这些命令的用户手册,就不需要在代码中重复这些信息。相反,在每个命令方法的接口注释中包含如下简短说明:

// Implements the Foo command; see the user manual for details.

读者可以轻松找到理解代码所需的所有文档,这一点很重要,但这并不意味着您必须编写所有这些文档。

The second technique for keeping comments up to date is to avoid duplication. If documentation is duplicated, it is more difficult for developers to find and update all of the relevant copies. Instead, try to document each design decision exactly once. If there are multiple places in the code that are affected by a particular decision, don’t repeat the documentation at each of these points. Instead, find the most obvious single place to put the documentation. For example, suppose there is tricky behavior related to a variable, which affects several different places where the variable is used. You can document that behavior in the comment next to the variable’s declaration. This is a natural place that developers are likely to check if they’re having trouble understanding code that uses the variable.

If there is no “obvious” single place to put a particular piece of documentation where developers will find it, create a designNotes file as described in Section 13.7. Or, pick the best of the available places and put the documentation there. In addition, add short comments in the other places that refer to the central location: “See the comment in xyz for an explanation of the code below.” If the reference becomes obsolete because the master comment was moved or deleted, this inconsistency will be self-evident because developers won’t find the comment at the indicated place; they can use revision control history to find out what happened to the comment and then update the reference. In contrast, if the documentation is duplicated and some of the copies don’t get updated, there will be no indication to developers that they are using stale information.

Don’t redocument one module’s design decisions in another module. For example, don’t put comments before a method call that explain what happens in the called method. If readers want to know, they should look at the interface comments for the method. Good development tools will usually provide this information automatically, for example, by displaying the interface comments for a method if you select the method’s name or hover the mouse over it. Try to make it easy for developers to find appropriate documentation, but don’t do it by repeating the documentation.

If information is already documented someplace outside your program, don’t repeat the documentation inside the program; just reference the external documentation. For example, if you write a class that implements the HTTP protocol, there’s no need for you to describe the HTTP protocol inside your code. There are already numerous sources for this documentation on the Web; just add a short comment to your code with a URL for one of these sources. Another example is features that are already documented in a user manual. Suppose you are writing a program that implements a collection of commands, with one method responsible for implementing each command. If there is a user manual that describes those commands, there’s no need to duplicate this information in the code. Instead, include a short note like the following in the interface comment for each command method:

// Implements the Foo command; see the user manual for details.

It’s important that readers can easily find all the documentation needed to understand your code, but that doesn’t mean you have to write all of that documentation.