[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;
}
~~~