高效Dart: 文档
今天很容易觉得自己的代码很清晰,但却没有意识到它大量的依赖于已在你当下大脑中的上下文。新接触这段代码的人,甚至是健忘的你自己未来都不会拥有这个上下文。简洁、精确的注释只需要花上几秒钟编写,但却可以为这些人节约几小时的时间。
我们都知道代码应该自己文档,很多注释并没有什么用。但现实是我们大部分人并没有编写足够的注释。这就如果健身,技术层面你可能会做得过渡了,但更多的可能是你做的太少了。试着加把劲吧。
注释
以下小贴士适用于你不希望放到自动生成文档中的注释。
要像句子一样格式化注释。
1 2 |
<span class="com">// Not if there is nothing before it.</span> <span class="kwd">if</span> <span class="pun">(</span><span class="pln">_chunks</span><span class="pun">.</span><span class="pln">isEmpty</span><span class="pun">)</span> <span class="kwd">return</span> <span class="kwd">false</span><span class="pun">;</span> |
除大小写敏感的标识符外均为第一个单词首字母大写。以逗号结尾(或是 ! 或 ?)。对于所有评论都是如此:文档评论、行内内容,甚至是TODO。哪怕是一个句子片断。
不要为文档使用块注释。
1 2 3 4 |
<span class="pln">greet</span><span class="pun">(</span><span class="pln">name</span><span class="pun">)</span> <span class="pun">{</span> <span class="com">// Assume we have a valid name.</span><span class="pln"> print</span><span class="pun">(</span><span class="str">'Hi, $name!'</span><span class="pun">);</span> <span class="pun">}</span> |
1 2 3 4 |
<span class="pln">greet</span><span class="pun">(</span><span class="pln">name</span><span class="pun">)</span> <span class="pun">{</span> <span class="com">/* Assume we have a valid name. */</span><span class="pln"> print</span><span class="pun">(</span><span class="str">'Hi, $name!'</span><span class="pun">);</span> <span class="pun">}</span> |
可以使用块注释 (/* ... */
) 来临时注释掉代码埠,但其实的注释应使用 //
。
文档注释
文档注释克斯方便,因为dartdoc 对它们进行解析并通过它们生成漂亮的文档页面。文档注释是出现在声明前并以dartdoc所查找特殊的语法 ///
开头的任意注释。
///
文档注释来对成员和类型建档。
要使用 Linter 规则: 文档注释的斜杠
使用文档注释代替普通的注释让 dartdoc 可以找到它并生成文档。
1 2 |
<span class="com">/// The number of characters in this chunk when unsplit.</span> <span class="typ">int</span> <span class="kwd">get</span><span class="pln"> length </span><span class="pun">=></span> <span class="pun">...</span> |
1 2 |
<span class="com">// The number of characters in this chunk when unsplit.</span> <span class="typ">int</span> <span class="kwd">get</span><span class="pln"> length </span><span class="pun">=></span> <span class="pun">...</span> |
出于历史原因,dartdoc支持两种文档注释的语句: ///
(C#样式) 和 /** ... */
(JavaDoc样式)。我们更倾向于 ///
,因它更为简洁。 /**
和 */
为多行文档注释增加了无内容行。 ///
在很多情况下也更易于阅读,比如在文档注释中使用*
来标记列表项时。
如果你撞到了仍在使用JavaDoc样式的代码时,请考虑进行清理。
推荐为公共API编写文档注释
无需对每个库、顶级变量、类型和成员建立文档,但应对大部分建立文档。
考虑使用一个库级文档注释
Unlike languages like Java where the class is the only unit of program organization, in Dart, a library is itself an entity that users work with directly, import, and think about. That makes the library
directive a great place for documentation that introduces the reader to the main concepts and functionality provided within. Consider including:
- A single-sentence summary of what the library is for.
- Explanations of terminology used throughout the library.
- A couple of complete code samples that walk through using the API.
- Links to the most important or most commonly used classes and functions.
- Links to external references on the domain the library is concerned with.
You document a library by placing a doc comment right above the library
directive at the start of the file. If the library doesn’t have a library
directive, you can add one just to hang the doc comment off of it.
考虑为私有API编写文档注释
Doc comments aren’t just for external consumers of your library’s public API. They can also be helpful for understanding private members that are called from other parts of the library.
要以单句总结开启文档注释
Start your doc comment with a brief, user-centric description ending with a period. A sentence fragment is often sufficient. Provide just enough context for the reader to orient themselves and decide if they should keep reading or look elsewhere for the solution to their problem.
1 2 3 4 |
<span class="com">/// Deletes the file at [path] from the file system.</span> <span class="typ">void</span><span class="pln"> delete</span><span class="pun">(</span><span class="typ">String</span><span class="pln"> path</span><span class="pun">)</span> <span class="pun">{</span> <span class="pun">...</span> <span class="pun">}</span> |
1 2 3 4 5 6 7 |
<span class="com">/// Depending on the state of the file system and the user's permissions,</span> <span class="com">/// certain operations may or may not be possible. If there is no file at</span> <span class="com">/// [path] or it can't be accessed, this function throws either [IOError]</span> <span class="com">/// or [PermissionError], respectively. Otherwise, this deletes the file.</span> <span class="typ">void</span><span class="pln"> delete</span><span class="pun">(</span><span class="typ">String</span><span class="pln"> path</span><span class="pun">)</span> <span class="pun">{</span> <span class="pun">...</span> <span class="pun">}</span> |
要将文档注释的第一句分隔为其自己的段落
Add a blank line after the first sentence to split it out into its own paragraph. If more than a single sentence of explanation is useful, put the rest in later paragraphs.
This helps you write a tight first sentence that summarizes the documentation. Also, tools like Dartdoc use the first paragraph as a short summary in places like lists of classes and members.
1 2 3 4 5 6 7 |
<span class="com">/// Deletes the file at [path].</span> <span class="com">///</span> <span class="com">/// Throws an [IOError] if the file could not be found. Throws a</span> <span class="com">/// [PermissionError] if the file is present but could not be deleted.</span> <span class="typ">void</span><span class="pln"> delete</span><span class="pun">(</span><span class="typ">String</span><span class="pln"> path</span><span class="pun">)</span> <span class="pun">{</span> <span class="pun">...</span> <span class="pun">}</span> |
1 2 3 4 5 6 |
<span class="com">/// Deletes the file at [path]. Throws an [IOError] if the file could not</span> <span class="com">/// be found. Throws a [PermissionError] if the file is present but could</span> <span class="com">/// not be deleted.</span> <span class="typ">void</span><span class="pln"> delete</span><span class="pun">(</span><span class="typ">String</span><span class="pln"> path</span><span class="pun">)</span> <span class="pun">{</span> <span class="pun">...</span> <span class="pun">}</span> |
避免通过带有周边上下文的冗余
The reader of a class’s doc comment can clearly see the name of the class, what interfaces it implements, etc. When reading docs for a member, the signature is right there, and the enclosing class is obvious. None of that needs to be spelled out in the doc comment. Instead, focus on explaining what the reader doesn’t already know.
1 2 3 4 5 6 7 |
<span class="kwd">class</span> <span class="typ">RadioButtonWidget</span> <span class="kwd">extends</span> <span class="typ">Widget</span> <span class="pun">{</span> <span class="com">/// Sets the tooltip to [lines], which should have been word wrapped using</span> <span class="com">/// the current font.</span> <span class="typ">void</span><span class="pln"> tooltip</span><span class="pun">(</span><span class="typ">List</span><span class="pun"><</span><span class="typ">String</span><span class="pun">></span><span class="pln"> lines</span><span class="pun">)</span> <span class="pun">{</span> <span class="pun">...</span> <span class="pun">}</span> <span class="pun">}</span> |
1 2 3 4 5 6 7 |
<span class="kwd">class</span> <span class="typ">RadioButtonWidget</span> <span class="kwd">extends</span> <span class="typ">Widget</span> <span class="pun">{</span> <span class="com">/// Sets the tooltip for this radio button widget to the list of strings in</span> <span class="com">/// [lines].</span> <span class="typ">void</span><span class="pln"> tooltip</span><span class="pun">(</span><span class="typ">List</span><span class="pun"><</span><span class="typ">String</span><span class="pun">></span><span class="pln"> lines</span><span class="pun">)</span> <span class="pun">{</span> <span class="pun">...</span> <span class="pun">}</span> <span class="pun">}</span> |
推荐以第三人称动词开启函数或方法注释
The doc comment should focus on what the code does.
1 2 3 4 5 6 7 |
<span class="com">/// Returns `true` if every element satisfies the [predicate].</span> <span class="typ">bool</span><span class="pln"> all</span><span class="pun">(</span><span class="typ">bool</span><span class="pln"> predicate</span><span class="pun">(</span><span class="typ">T</span><span class="pln"> element</span><span class="pun">))</span> <span class="pun">=></span> <span class="pun">...</span> <span class="com">/// Starts the stopwatch if not already running.</span> <span class="typ">void</span><span class="pln"> start</span><span class="pun">()</span> <span class="pun">{</span> <span class="pun">...</span> <span class="pun">}</span> |
推荐以名词词组开始的变量、getter或setter注释
The doc comment should stress what the property is. This is true even for getters which may do calculation or other work. What the caller cares about is the result of that work, not the work itself.
1 2 3 4 5 |
<span class="com">/// The current day of the week, where `0` is Sunday.</span> <span class="typ">int</span><span class="pln"> weekday</span><span class="pun">;</span> <span class="com">/// The number of checked buttons on the page.</span> <span class="typ">int</span> <span class="kwd">get</span><span class="pln"> checkedCount </span><span class="pun">=></span> <span class="pun">...</span> |
Avoid having a doc comment on both the setter and the getter, as DartDoc will show only one (the one on the getter.)
推荐以名词词组开始的库或类型注释
Doc comments for classes are often the most important documentation in your program. They describe the type’s invariants, establish the terminology it uses, and provide context to the other doc comments for the class’s members. A little extra effort here can make all of the other members simpler to document.
1 2 3 4 |
<span class="com">/// A chunk of non-breaking output text terminated by a hard or soft newline.</span> <span class="com">///</span> <span class="com">/// ...</span> <span class="kwd">class</span> <span class="typ">Chunk</span> <span class="pun">{</span> <span class="pun">...</span> <span class="pun">}</span> |
CONSIDER including code samples in doc comments.
1 2 3 4 5 6 |
<span class="com">/// Returns the lesser of two numbers.</span> <span class="com">///</span> <span class="com">/// ```dart</span> <span class="com">/// min(5, 3) == 3</span> <span class="com">/// ```</span> <span class="typ">num</span><span class="pln"> min</span><span class="pun">(</span><span class="typ">num</span><span class="pln"> a</span><span class="pun">,</span> <span class="typ">num</span><span class="pln"> b</span><span class="pun">)</span> <span class="pun">=></span> <span class="pun">...</span> |
Humans are great at generalizing from examples, so even a single code sample makes an API easier to learn.
DO use square brackets in doc comments to refer to in-scope identifiers.
Linter rule: comment_references
If you surround things like variable, method, or type names in square brackets, then dartdoc looks up the name and links to the relevant API docs. Parentheses are optional, but can make it clearer when you’re referring to a method or constructor.
1 2 |
<span class="com">/// Throws a [StateError] if ...</span> <span class="com">/// similar to [anotherMethod()], but ...</span> |
To link to a member of a specific class, use the class name and member name, separated by a dot:
1 |
<span class="com">/// Similar to [Duration.inDays], but handles fractional days.</span> |
The dot syntax can also be used to refer to named constructors. For the unnamed constructor, put parentheses after the class name:
1 |
<span class="com">/// To create a point, call [Point()] or use [Point.polar()] to ...</span> |
DO use prose to explain parameters, return values, and exceptions.
Other languages use verbose tags and sections to describe what the parameters and returns of a method are.
1 2 3 4 5 6 7 8 |
<span class="com">/// Defines a flag with the given name and abbreviation.</span> <span class="com">///</span> <span class="com">/// @param name The name of the flag.</span> <span class="com">/// @param abbr The abbreviation for the flag.</span> <span class="com">/// @returns The new flag.</span> <span class="com">/// @throws ArgumentError If there is already an option with</span> <span class="com">/// the given name or abbreviation.</span> <span class="typ">Flag</span><span class="pln"> addFlag</span><span class="pun">(</span><span class="typ">String</span><span class="pln"> name</span><span class="pun">,</span> <span class="typ">String</span><span class="pln"> abbr</span><span class="pun">)</span> <span class="pun">=></span> <span class="pun">...</span> |
The convention in Dart is to integrate that into the description of the method and highlight parameters using square brackets.
1 2 3 4 5 |
<span class="com">/// Defines a flag.</span> <span class="com">///</span> <span class="com">/// Throws an [ArgumentError] if there is already an option named [name] or</span> <span class="com">/// there is already an option using abbreviation [abbr]. Returns the new flag.</span> <span class="typ">Flag</span><span class="pln"> addFlag</span><span class="pun">(</span><span class="typ">String</span><span class="pln"> name</span><span class="pun">,</span> <span class="typ">String</span><span class="pln"> abbr</span><span class="pun">)</span> <span class="pun">=></span> <span class="pun">...</span> |
DO put doc comments before metadata annotations.
1 2 3 |
<span class="com">/// A button that can be flipped on and off.</span><span class="pln"> @</span><span class="typ">Component</span><span class="pun">(</span><span class="pln">selector</span><span class="pun">:</span> <span class="str">'toggle'</span><span class="pun">)</span> <span class="kwd">class</span> <span class="typ">ToggleComponent</span> <span class="pun">{}</span> |
1 2 3 |
<span class="pln">@</span><span class="typ">Component</span><span class="pun">(</span><span class="pln">selector</span><span class="pun">:</span> <span class="str">'toggle'</span><span class="pun">)</span> <span class="com">/// A button that can be flipped on and off.</span> <span class="kwd">class</span> <span class="typ">ToggleComponent</span> <span class="pun">{}</span> |
Markdown
You are allowed to use most markdown formatting in your doc comments and dartdoc will process it accordingly using the markdown package.
There are tons of guides out there already to introduce you to Markdown. Its universal popularity is why we chose it. Here’s just a quick example to give you a flavor of what’s supported:
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 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 |
<span class="com">/// This is a paragraph of regular text.</span> <span class="com">///</span> <span class="com">/// This sentence has *two* _emphasized_ words (italics) and **two**</span> <span class="com">/// __strong__ ones (bold).</span> <span class="com">///</span> <span class="com">/// A blank line creates a separate paragraph. It has some `inline code`</span> <span class="com">/// delimited using backticks.</span> <span class="com">///</span> <span class="com">/// * Unordered lists.</span> <span class="com">/// * Look like ASCII bullet lists.</span> <span class="com">/// * You can also use `-` or `+`.</span> <span class="com">///</span> <span class="com">/// 1. Numbered lists.</span> <span class="com">/// 2. Are, well, numbered.</span> <span class="com">/// 1. But the values don't matter.</span> <span class="com">///</span> <span class="com">/// * You can nest lists too.</span> <span class="com">/// * They must be indented at least 4 spaces.</span> <span class="com">/// * (Well, 5 including the space after `///`.)</span> <span class="com">///</span> <span class="com">/// Code blocks are fenced in triple backticks:</span> <span class="com">///</span> <span class="com">/// ```</span> <span class="com">/// this.code</span> <span class="com">/// .will</span> <span class="com">/// .retain(its, formatting);</span> <span class="com">/// ```</span> <span class="com">///</span> <span class="com">/// The code language (for syntax highlighting) defaults to Dart. You can</span> <span class="com">/// specify it by putting the name of the language after the opening backticks:</span> <span class="com">///</span> <span class="com">/// ```html</span> <span class="com">/// <h1>HTML is magical!</h1></span> <span class="com">/// ```</span> <span class="com">///</span> <span class="com">/// Links can be:</span> <span class="com">///</span> <span class="com">/// * http://www.just-a-bare-url.com</span> <span class="com">/// * [with the URL inline](http://google.com)</span> <span class="com">/// * [or separated out][ref link]</span> <span class="com">///</span> <span class="com">/// [ref link]: http://google.com</span> <span class="com">///</span> <span class="com">/// # A Header</span> <span class="com">///</span> <span class="com">/// ## A subheader</span> <span class="com">///</span> <span class="com">/// ### A subsubheader</span> <span class="com">///</span> <span class="com">/// #### If you need this many levels of headers, you're doing it wrong</span> |
避免过渡使用markdown
When in doubt, format less. Formatting exists to illuminate your content, not replace it. Words are what matter.
AVOID using HTML for formatting.
It may be useful to use it in rare cases for things like tables, but in almost all cases, if it’s too complex too express in Markdown, you’re better off not expressing it.
PREFER backtick fences for code blocks.
Markdown has two ways to indicate a block of code: indenting the code four spaces on each line, or surrounding it in a pair of triple-backtick “fence” lines. The former syntax is brittle when used inside things like Markdown lists where indentation is already meaningful or when the code block itself contains indented code.
The backtick syntax avoids those indentation woes, lets you indicate the code’s language, and is consistent with using backticks for inline code.
1 2 3 4 5 6 |
<span class="com">/// You can use [CodeBlockExample] like this:</span> <span class="com">///</span> <span class="com">/// ```</span> <span class="com">/// var example = CodeBlockExample();</span> <span class="com">/// print(example.isItGreat); // "Yes."</span> <span class="com">/// ```</span> |
1 2 3 4 |
<span class="com">/// You can use [CodeBlockExample] like this:</span> <span class="com">///</span> <span class="com">/// var example = CodeBlockExample();</span> <span class="com">/// print(example.isItGreat); // "Yes."</span> |
编写
We think of ourselves as programmers, but most of the characters in a source file are intended primarily for humans to read. English is the language we code in to modify the brains of our coworkers. As for any programming language, it’s worth putting effort into improving your proficiency.
This section lists a few guidelines for our docs. You can learn more about best practices for technical writing, in general, from articles such asTechnical writing style.
推荐保持简洁
Be clear and precise, but also terse.
AVOID abbreviations and acronyms unless they are obvious.
Many people don’t know what “i.e.”, “e.g.” and “et al.” mean. That acronym that you’re sure everyone in your field knows may not be as widely known as you think.
推荐使用this代替the来引用成员的实例
When documenting a member for a class, you often need to refer back to the object the member is being called on. Using “the” can be ambiguous.
1 2 3 4 5 6 7 |
<span class="kwd">class</span> <span class="typ">Box</span> <span class="pun">{</span> <span class="com">/// The value this wraps.</span> <span class="kwd">var</span><span class="pln"> _value</span><span class="pun">;</span> <span class="com">/// True if this box contains a value.</span> <span class="typ">bool</span> <span class="kwd">get</span><span class="pln"> hasValue </span><span class="pun">=></span><span class="pln"> _value </span><span class="pun">!=</span> <span class="kwd">null</span><span class="pun">;</span> <span class="pun">}</span> |