[TOC]
你今天可能觉得你的代码很容易看懂,是显而易见的。但是你忽略了你已经在自己的脑海中构建了依赖的上下文关系。但是对于其他人去看你的代码,或者是隔了很久之后你自己去查看自己的代码,都不会有这样已经建立在脑海中的上下文关系。这个时候如果是有代码注释可能会节省更多的时间。往往我们花很少的时间就能完成代码注释。
我们都知道代码应该是自文档化的,并不是所有的注释都是有用的。但现实是,我们中的大多数人并没有写出我们应该写的那么多注释。这就像锻炼:你在技术上可以做得太多,但更有可能你做得太少了。试着提高它。
## 注释
以下技巧适用于您不希望包含在生成文档中的注释。
### 要像句子一样格式化评论。
~~~
// Not if there is nothing before it.
if (_chunks.isEmpty) return false;
~~~
除非是区分大小写的标识符,否则第一个单词要大写。以句号结尾(或“!”或“?”)。对于所有的注释都是如此:doc注释、内联内容,甚至TODOs。即使是一个句子片段。
### 不要在文档中使用块注释。
~~~
greet(name) {
// Assume we have a valid name.
print('Hi, $name!');
}
~~~
以下是错误示例。
~~~
greet(name) {
/* Assume we have a valid name. */
print('Hi, $name!');
}
~~~
你可以使用块注释(/*…*/)临时注释掉一段代码,但是所有其他注释都应该使用//。
## Doc注释
Doc注释特别方便,因为dartdoc解析它们并从中生成漂亮的Doc页面。doc注释是任何出现在声明前并使用特殊///语法的注释。
### 使用///文档注释来记录成员和类型。
使用doc注释而不是常规注释,可以让dartdoc找到并生成文档。
~~~
/// The number of characters in this chunk when unsplit.
int get length => ...
~~~
以下是错误示例。
~~~
// The number of characters in this chunk when unsplit.
int get length => ...
~~~
由于历史原因,达特茅斯学院支持道格评论的两种语法:///(“C#风格”)和/**…* /(“JavaDoc风格”)。我们更喜欢/// 因为它更紧凑。/\*\*和*/在多行文档注释中添加两个无内容的行。在某些情况下,///语法也更容易阅读,例如文档注释包含使用*标记列表项的项目符号列表。
如果您发现代码仍然使用JavaDoc样式,请考虑清理它。
### 优先为公共api编写文档注释。
您不必为每个库、顶级变量、类型和成员编制文档,但您应该为它们中的大多数编制文档。
### 考虑写一个库级别的文档注释
与Java等语言不同,在Dart中,类是程序组织的唯一单位,库本身是用户直接使用、导入和思考的实体。这使得library directive提供了一个很好的文档空间,向读者介绍了库中提供的主要概念和功能。考虑包括:
* 用一句话概括库的用途。
* 解释整个库使用的术语。
* 两个完整的代码示例使用API遍历。
* 链接到最重要或最常用的类和函数。
* 链接到与库有关的领域的外部引用。
您可以通过在文件开头的库指令上方放置一个doc注释来记录一个库。如果库没有一个库指令,你可以添加一个来挂掉文档注释。
### 考虑为私有api编写文档注释。
Doc注释并不仅仅针对库的公共API的外部使用者。它们还有助于理解从库的其他部分调用的私有成员。
### 用一句话总结开始doc注释。
以简短的、以用户为中心的描述开始你的文档注释,以句号结尾。一个句子片段通常就足够了。为读者提供足够的上下文,使他们能够确定自己的方向,并决定是否应该继续阅读或在别处寻找问题的解决方案。
~~~
/// Deletes the file at [path] from the file system.
void delete(String path) {
...
}
~~~
以下是错误示例。
~~~
/// Depending on the state of the file system and the user's permissions,
/// certain operations may or may not be possible. If there is no file at
/// [path] or it can't be accessed, this function throws either [IOError]
/// or [PermissionError], respectively. Otherwise, this deletes the file.
void delete(String path) {
...
}
~~~
### 一定要把“doc注释”的第一句话分隔成自己的段落。
在第一个句子之后添加一个空行,把它分成自己的段落。如果一个以上的解释是有用的,把其余的放在后面的段落。
这有助于您编写一个紧凑的第一句话,总结文档。同样,工具如达特茅斯学院使用第一段作为一个简短的总结,如类和成员列表。
~~~
/// Deletes the file at [path].
///
/// Throws an [IOError] if the file could not be found. Throws a
/// [PermissionError] if the file is present but could not be deleted.
void delete(String path) {
...
}
~~~
以下是错误示例。
~~~
/// Deletes the file at [path]. Throws an [IOError] if the file could not
/// be found. Throws a [PermissionError] if the file is present but could
/// not be deleted.
void delete(String path) {
...
}
~~~
### 避免与周围的上下文冗余。
类文档注释的读者可以清楚地看到类的名称、它实现的接口等。这些都不需要在doc注释中说明。相反,要专注于解释读者还不知道的东西。
~~~
class RadioButtonWidget extends Widget {
/// Sets the tooltip to [lines], which should have been word wrapped using
/// the current font.
void tooltip(List<String> lines) {
...
}
}
~~~
以下是错误示例。
~~~
class RadioButtonWidget extends Widget {
/// Sets the tooltip for this radio button widget to the list of strings in
/// [lines].
void tooltip(List<String> lines) {
...
}
}
~~~
### 优先用第三人称动词开始函数或方法注释。
doc注释应该关注代码的功能。
~~~
/// Returns `true` if every element satisfies the [predicate].
bool all(bool predicate(T element)) => ...
/// Starts the stopwatch if not already running.
void start() {
...
}
~~~
### 优先用名词短语开始变量、getter或setter注释。
doc注释应该强调属性是什么。即使对于做计算或其他工作的getter也是如此。调用者关心的是工作的结果,而不是工作本身。
~~~
/// The current day of the week, where `0` is Sunday.
int weekday;
/// The number of checked buttons on the page.
int get checkedCount => ...
~~~
避免在setter和getter上都有doc注释,因为dardoc只会显示一个注释(getter上的注释)。
### 优先从库开始,或者用名词短语输入注释。
类的文档注释通常是程序中最重要的文档。它们描述了类型的不变量,建立了它使用的术语,并为类的成员提供了其他文档注释的上下文。在这里做一点额外的工作可以使所有其他成员更容易记录。
~~~
/// A chunk of non-breaking output text terminated by a hard or soft newline.
///
/// ...
class Chunk { ... }
~~~
### 考虑在doc注释中包含代码示例。
~~~
/// Returns the lesser of two numbers.
///
/// ```dart
/// min(5, 3) == 3
/// ```
num min(num a, num b) => ...
~~~
人类擅长从示例中归纳,因此即使是一个代码示例也能使API更容易学习。
### 请务必在doc注释中使用方括号来引用范围内的标识符。
如果将变量、方法或类型名称放在方括号中,那么dardoc会查找名称并链接到相关的API文档。圆括号是可选的,但在引用方法或构造函数时可以使它更清楚。
~~~
/// Throws a [StateError] if ...
/// similar to [anotherMethod()], but ...
~~~
要链接到特定类的成员,使用类名和成员名,用点分隔:
~~~
/// Similar to [Duration.inDays], but handles fractional days.
~~~
点语法还可以用于引用指定的构造函数。对于未命名的构造函数,在类名后加括号:
~~~
/// To create a point, call [Point()] or use [Point.polar()] to ...
~~~
### 务必使用白话文来解释参数、返回值和异常。
其他语言使用详细标记和部分来描述方法的参数和返回值。
以下是错误示例:
~~~
/// Defines a flag with the given name and abbreviation.
///
/// @param name The name of the flag.
/// @param abbr The abbreviation for the flag.
/// @returns The new flag.
/// @throws ArgumentError If there is already an option with
/// the given name or abbreviation.
Flag addFlag(String name, String abbr) => ...
~~~
Dart中的约定是将其集成到方法描述中,并使用方括号突出显示参数。
~~~
/// Defines a flag.
///
/// Throws an [ArgumentError] if there is already an option named [name] or
/// there is already an option using abbreviation [abbr]. Returns the new flag.
Flag addFlag(String name, String abbr) => ...
~~~
### 一定要在元数据注释之前加上doc注释。
~~~
/// A button that can be flipped on and off.
@Component(selector: 'toggle')
class ToggleComponent {}
~~~
以下是错误示例:
~~~
@Component(selector: 'toggle')
/// A button that can be flipped on and off.
class ToggleComponent {}
~~~
## Markdown
您可以在文档注释中使用大多数标记格式,而dartdoc将使用Markdown包对其进行相应处理。
市面上已经有大量的指南向你介绍Markdown。它的普遍流行就是我们选择它的原因。下面是一个简单的例子,让您了解支持什么:
~~~
/// This is a paragraph of regular text.
///
/// This sentence has *two* _emphasized_ words (italics) and **two**
/// __strong__ ones (bold).
///
/// A blank line creates a separate paragraph. It has some `inline code`
/// delimited using backticks.
///
/// * Unordered lists.
/// * Look like ASCII bullet lists.
/// * You can also use `-` or `+`.
///
/// 1. Numbered lists.
/// 2. Are, well, numbered.
/// 1. But the values don't matter.
///
/// * You can nest lists too.
/// * They must be indented at least 4 spaces.
/// * (Well, 5 including the space after `///`.)
///
/// Code blocks are fenced in triple backticks:
///
/// ```
/// this.code
/// .will
/// .retain(its, formatting);
/// ```
///
/// The code language (for syntax highlighting) defaults to Dart. You can
/// specify it by putting the name of the language after the opening backticks:
///
/// ```html
/// <h1>HTML is magical!</h1>
/// ```
///
/// Links can be:
///
/// * http://www.just-a-bare-url.com
/// * [with the URL inline](http://google.com)
/// * [or separated out][ref link]
///
/// [ref link]: http://google.com
///
/// # A Header
///
/// ## A subheader
///
/// ### A subsubheader
///
/// #### If you need this many levels of headers, you're doing it wrong
~~~
### 避免使用过度减记。
如果有疑问,减少格式。格式化的存在是为了让您的内容容易读,而不是替换它。单词是最重要的。
### 避免使用HTML进行格式化。
在很少的情况下,例如表,使用它可能很有用,但是在几乎所有情况下,如果它过于复杂,在Markdown中过于表达,最好不要表达它。
### 优先用反引号包围代码块。
Markdown有两种方法来表示代码块:在每行上缩进代码4个空格,或者在一对三个反引号的“fence”行中包围代码块。前一种语法在标记列表(缩进已经有意义)或代码块本身包含缩进代码时很脆弱。
backtick语法避免了这些缩进问题,允许您指示代码的语言,并且与使用反引号对内联代码保持一致。
~~~
/// You can use [CodeBlockExample] like this:
///
/// ```
/// var example = CodeBlockExample();
/// print(example.isItGreat); // "Yes."
/// ```
~~~
以下是错误示例:
~~~
/// You can use [CodeBlockExample] like this:
///
/// var example = CodeBlockExample();
/// print(example.isItGreat); // "Yes."
~~~
## 写注释
我们认为自己是程序员,但是源文件中的大多数字符主要是供人阅读的。英语是我们用来修改同事大脑的语言。对于任何一种编程语言来说,努力提高你的熟练程度都是值得的。
这部分列出了我们的文档的一些指南。一般来说,您可以从技术写作风格之类的文章中了解更多关于技术写作的最佳实践。
### 优先注意简洁。
要清晰、准确,但也要简洁。
### 避免使用缩写和首字母缩写,除非它们很明显。
很多人都不知道。”i.e.",“e.g."和“et al.”的意思。你确信你所在领域的每个人都知道的那个缩略语可能并不像你想象的那样广为人知。
### 优先使用“this”而不是“the”来引用成员的实例。
当为一个类记录一个成员时,您通常需要引用调用该成员的对象。使用“the”可能是模棱两可的。
~~~
class Box {
/// The value this wraps.
var _value;
/// True if this box contains a value.
bool get hasValue => _value != null;
}
~~~