項目27:パブリックインターフェイスのドキュメントを書こう
https://effective-rust.com/documentation.html
LT;DR
パブリック API にはドキュメントを書こう
コードからは分からないことを書こう
e.g.
前提条件
不変条件
panic(#Panics)が起こる条件
unsafe なコードが必要とする条件(#Safety)
意思決定(「なぜそうしたか」、「なぜそうしなかったか」)
コメントはコードの近くに配置すること
識別子 にはクロスリファレンスを与えて、可読性 を上げよう
hr.icon
ある クレート が別のプログラマ(未来の自分も含む)に使われるのであれば、パブリック API のドキュメントを用意すること
ドキュメントコメント
Rust では、/// または //! を用いると ドキュメンテーションコメント( Markdown 形式)が記述可能
https://doc.rust-jp.rs/book-ja/ch14-02-publishing-to-crates-io.html#役に立つドキュメンテーションコメントを行う
code:rs
/// 2 つの [BoundingBox] を正確に包含する [BoudingBox] を計算する
pub fn union(a: &BoundingBox, b: &BoundingBox) -> BoundingBox {
// ...
}
注意点
コードはコードフォントを使う(` で囲む)
識別子 にクロスリファレンスを書く
以下のように書くことで、Something がスコープ内にあればそれに対する ハイパーリンク がドキュメントに付与される
code:md
[Something]
#Examples セクションにサンプルコードを書く
warning.icon このコードは cargo test 時にコンパイルされ、実行される
項目30:ユニットテスト以上のものを書こう
#Panics セクションに panic を起こさないために必要な前提条件を書く
#Safety セクションに unsafe なコードが必要とする前提条件を書く
どう書くか困った際には、標準ライブラリを参考にすると良い
ドキュメントの生成
cargo doc を実行すると、ドキュメンテーションコメントからドキュメントを生成できる
ドキュメントを書いたら「レンダリングされたドキュメントを読もう」
読むには、--open または --no-deps --open(現在のクレートにドキュメントを限定する) オプションを付与する
関連する Lint 項目
broken_intra_doc_links: 生成されたすべてのハイパーリンクが有効であることをチェックする
code:rs
#!deny(brokbroken_intra_doc_links)
/// [Polygon] のバウンディングボックス
#derive(Clone, Debug)
pub struct BoundingBox {
// ...
}
上記のコードは Polygon のドキュメントが無い場合に、警告を出す
code:_
warning: unresolved link to Polygon
--> docs/src/main.rs:4:30
|
4 | /// [Polygon] のバウンディングボックス
| ^^^^^^^^^ no item named Polygon in scope
missing_docs: ドキュメントが存在するかチェックする
warning.icon ドキュメントの品質が低下する危険性がある
上記の Lint は CI で走らせると良い(項目32:CIシステムを設定しよう)
ドキュメントを置く場所
ドキュメントは cargo doc の出力先(デフォルトでは target/doc)だが、別のディレクトリに置いても良い
e.g. examples サブディレクトリ
クレートを利用したバイナリコードを置く場所としてよく用いられる
このプログラムは 統合テスト と同じようにビルドされて実行される(cargo run --example <example_name>)が、API の正しい使い方を示すサンプルコードとなる
tests/ ディレクトリ以下の統合テストも同様
公開されたクレートのドキュメント
クレートを crates.io に公開すると、ドキュメントは docs.rs に公開される
docs.rs: cargo doc の出力のトップレベルページが表示される
トップレベルページは、src/lib.rs ファイルのトップレベルの //! コメント から生成される
crates.io: リポジトリのトップレベルの README.md
ドキュメントに書くべきでないこと
「コードから分かることはドキュメントに書かない」
類似: コメントは抽象的にすること
シグネチャ や 型 から明らかなことは書いてはいけない
これを書いてしまうと、コードとコメントとで 不整合 が起きやすくなる
e.g. リファクタリング する際にコメントも変更する必要があるが、IDE 上では指摘されない
e.g.
code:rs
/// 2 つの [BoundingBox] を正確に包含する [BoudingBox] の新しいインスタンスを返す
///
/// 引数:
/// - 'a': BoundingBox に対する不変参照
/// - 'b': BoundingBox に対する不変参照
/// 戻り値: 新しい BoundingBox インスタンス
pub fn union(a: &BoundingBox, b: &BoundingBox) -> BoundingBox {
a の型を変えるとコメントと 不整合 が起きる
code:rs
pub fn union(a: &mut BoundingBox, b: &BoundingBox) -> BoundingBox {
言い換えると、「コードから明らかでないことはすべて、ドキュメントに書こう」
e.g. 前提条件 や 不変条件、panic、エラー条件 ...
コードが 驚き最小の原則 に従うように
メソッドを使用している他のコードについて書かない
e.g.
code:rs
/// 2 つの [BoundingBox] インスタンスの重なった部分を返す。
/// 重なりがなければ None を返す。
/// hits.rs 内の衝突判定コードが、object.overlap によるコストの高いピクセル単位のチェックを行う、
/// 事前チェックとしてこのメソッドを用いて 2 つのオブジェクトが重なるかどうかを判定する。
pub intersection(
a: &BoundingBox,
b: &BoundingBox,
) -> Option<BoundingBox> {
このようなコメントは、メソッドを使用するコード(hits.rs)を変更する際に 不整合 を起こす可能性が高い
コメントはコードの近くに配置すること
改善案
code:rs
/// 2 つの [BoundingBox] インスタンスの重なった部分を返す。
/// 重なりがなければ None を返す。
/// バウンディングボックスに重なりがあるということは衝突の必要条件ではあるが十分条件ではないため、重なった部分に
/// 対してピクセル単位のチェックが必要。
コードを書く際のアドバイス「未来形でプログラミングを行おう」はドキュメントにも当てはまる
そのためには、コメントは 意思決定 に焦点を当てて記述すべきである
#Rust #Effective_Rust_―_Rustコードを改善し、エコシステムを最大限に活用するための35項目