‼️

ライブラリ製作者に知ってほしい、examplesの3箇条

に公開

Rust言語のライブラリのソースコードをリポジトリで公開する際、慣例的にexamplesというディレクトリが用意されていることが多いです。
このexamplesの配下にはライブラリの使い方を示すサンプルコードが置かれており、初めてそのライブラリを触るユーザーをガイドするという重要な役割を果たしています。
この記事ではより良い例の書き方について、私が意識していることを3つ紹介します。

先に伝えたいことだけまとめると、コードは最小構成にし、ユーザーが段階を踏んで例を確認できるような構成にしましょう。

simple.rsを用意する

これ地味に重要です。
simple.rsは初めて使うユーザーにとっての入り口になります。
逆に言えばこれがない場合ユーザーはどこから見ていいのか分からなくなってしまいます。
なお、simpleという名前である必要はありません。例えばindexとかhello_worldとかとにかく最初に見てほしいんだなと伝われば問題ありません。
ただ慣例的にsimple.rsが多いのでこの名前が無難だと思います。

このファイルではライブラリの基本動作を知ってもらうために最小構成のコードを書きましょう。
自分のライブラリの例を挙げると、bevy_vrm1というBevyでVRMモデルを扱うライブラリではVRMモデルを1体読み込むだけのコードになっています。(なお、カメラやライトのスポーンもしていますが必須なのでお許しください)
https://github.com/not-elm/bevy_vrm1/blob/main/examples/simple.rs

その他のライブラリのsimple.rs

機能別に用意する

simple.rsをみて基本動作を把握したユーザーはそこで初めてライブラリの詳細な機能を知りたいと思うでしょう。
examplesディレクトリ配下には複数のファイルを配置できるため機能ごとに分けて説明しましょう。
また、README.mdに機能毎に項目を用意し、examplesと関連づけておくことをお勧めします。
これについては自分も最近意識し始めており、bevy_vrm1で取り入れています。

最低限のコードだけ書くようにする

最も重要ですが、意外とできていないプロジェクトが多い気がします。
自分はBevyというゲームエンジンのライブラリの例をよく見ているのですが、よくありがちなのは無駄にUIやアニメーションを凝るパターンです。
特にUIテキストでキーの操作を表示しているのは公式の例でも見かけますが、個人的にはコードを見る上でノイズとなるためあまり好きではありません。
代わりにコメントに示すのがいいと思います。

//! キーの説明
//! - `W`: 前進

fn main() {
    // ここにコードを書く
}

理想的なコード数

理想的なコード数は100行以下です。多くても150行以内に収めるのが望ましいです。
ただし、この行数にはコメントは含めないものとします。

また、例外としてどうしても1機能を説明するのに行数が必要になるケースもあります。
ただし、このようなケースはかなり特殊であり、ライブラリの低層部分を触らせる必要がある場合に限ります。
逆に低層以外の機能を説明するのに行数が必要となっている場合、ライブラリの設計を見直した方がいいかもしれません。

実際の例としては以下のようなものがあります。
これはBevyのexamplesの1つで、メインの描画パスの後に独自の描画パスを追加する例です。
この例は600行を超えていますが、描画パスを追加すること自体特殊かつ低層の機能であるため、先ほど説明した例外の1つに該当します。
https://github.com/bevyengine/bevy/blob/release-0.16.1/examples/shader/custom_render_phase.rs

GUIが必要か再度検討する

以下は私が製作しているBevyでコルーチンを使うためのライブラリbevy_flurxのものです。
この例ではUndo/Redoの機能を説明しており、矩形を上下左右に移動させ右のパネルに表示されている操作履歴からUndo/Redoを出来るようにしていました。
コードを見ていただくと分かると思いますが、eguiの描画処理などがノイズとなり肝心のUndo/Redoの処理が把握しにくくなっています。

https://github.com/not-elm/bevy_flurx/blob/v0.10.0/examples/undo_redo.rs

eguiを知らない人からすれば本質と関係ないところで悩まされることになります。
そもそもUndo/Redoを説明するだけならばGUIを使わず、コンソール出力だけで十分です。
書き直されたコードは以下で、元々200行あったのが半分の100行になりました。
https://github.com/not-elm/bevy_flurx/blob/v0.11.0/examples/undo_redo.rs

より実践的なexamplesの書き方(番外1)

より実践的な例を書きたい場合があると思います。 例えばBevy系だと簡単なゲームを作るなどです。
このような例はゆうに1000行を超えるコードが多いですが、何も考えずにexamplesに配置し、運悪くユーザーがその例を最初に見てしまったらどうなるでしょうか?
ほとんどのユーザーはいきなり1000行を超えるコードを浴びせられ、気圧され、そっとIDEを閉じてしまうでしょう。
ただ、そのような例に需要がないというわけではなく、機能を把握してきて実際に自分のアプリを作ろうとする段階のユーザーからすればありがたい存在です。
最初にも述べたようにexamplesで重要なのは段階です。つまり、「この例は最初に見るものではなく実践を想定していますよ」という想いが伝わるようにすればいいわけです。
このような例は別クレートとしてexamplesディレクトリの中に用意する(以下参照)、または別リポジトリとして公開し、ライブラリのリポジトリからサブモジュールとしてリンクする、またはREADMEにリンクを貼っておくのがおすすめです。
また、README.mdを用意して実践的な例であることを明記しておくと親切です。

└── examples
    └── game
        └── src
        ├   ├── main.rs
        ├── Cargo.toml
        └── README.md

サムネ用のexamplesについて(番外2)

README.mdにサムネイルとして載せる用の例を作るケースもあります。私の例で言うとbevy_flurxのcut_in.rsです。

https://github.com/not-elm/bevy_flurx/blob/v0.11.0/examples/cut_in.rs

このようなケースでは見栄えを重視する傾向にあるため自然とコード量が増えてしまいます。
そのため、本来は上記の通り別クレートとかに分離したほうがいいかもしれません。

Discussion