1. 程式人生 > >編寫高質量Dart程式-文件註釋參考

編寫高質量Dart程式-文件註釋參考

你今天可能覺得你的程式碼很容易看懂,是顯而易見的。但是你忽略了你已經在自己的腦海中構建了依賴的上下文關係。但是對於其他人去看你的程式碼,或者是隔了很久之後你自己去檢視自己的程式碼,都不會有這樣已經建立在腦海中的上下文關係。這個時候如果是有程式碼註釋可能會節省更多的時間。往往我們花很少的時間就能完成程式碼註釋。

我們都知道程式碼應該是自文件化的,並不是所有的註釋都是有用的。但現實是,我們中的大多數人並沒有寫出我們應該寫的那麼多註釋。這就像鍛鍊:你在技術上可以做得太多,但更有可能你做得太少了。試著提高它。

註釋

以下技巧適用於您不希望包含在生成文件中的註釋。

要像句子一樣格式化評論。

// 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;
}