”README”の語源は何でしょうか?
この命名は、 少なくとも 1970 年代のPDP-10まで遡りますが、もしかしたらパンチカードの束の上に「READ ME!」と書かれた紙のメモを置いて、使い方を説明していた時代まで遡るかもしれません。
読者の方1から、README はルイス・キャロルの 不思議の国のアリス に登場する "DRINK ME" と書かれた飲み薬や "EAT ME" と書かれたケーキを意識しているのでは、とも指摘していただきました。
README は歴史的にすべて大文字で表記されてきました。すべて大文字を使用することで、視覚的なインパクトがあることに加え、UNIX システムは小文字の前に大文字をソートするので、ディレクトリ内の他のコンテンツ2より README を優先させることができます。
その意図は明確で、"この情報はユーザーが先に進む前に読むべき重要な情報です" ということです。ではこの現代において、”重要な情報”とは何なのか一緒に探ってみましょう。
本記事は README についての記事です。README が何をするのか、なぜ絶対に必要なのか、そしてどのようにうまく作るのかについて書かれています。
本記事はモジュールの製作者向けに書かれたものです。モジュールの製作者の仕事は、長く使えるものを作ることです。これは、たとえ製作者が自分の作品を共有するつもりがないとしても、内発的な動機でしょう。6 ヶ月も経つと、ドキュメントのないモジュールは、製作者にも見慣れないものに見えてきます。
本記事はまた、モジュールのユーザー向けにも書かれています。すべてのモジュール製作者は、モジュールのユーザーでもあります。Node は非常に健全な相互依存性を持っており、依存関係ツリーの最下部には、ひとつもモジュールはありません。
ここでは Node に焦点を当てていますが、筆者はその教訓は他のプログラミング言語のエコシステムにも応用できると考えています。
Node のエコシステムは、モジュールによって支えられています。npmは、それを実現するための魔法です。Node 開発者は彼らのプロジェクトに含まれる何十ものモジュールを短い間に評価します。npm install
とさえ書ければ、日々の業務に有益なモジュールを引っ張ってこれるのは、すごいことです。
アクセスしやすいエコシステムでは良くあることですが、モジュールの品質にはばらつきがあります。npm はモジュールをすべてきれいに梱包して広く届けるために最善を尽くしています。しかし、発見できるツールは多種多様で、ピカピカで新しいものもあれば、壊れて錆びついたものもあり、またその中間のものもあります。中には、何をするものなのか分からないものまであります!
モジュールで言えば、不正確な名前や役に立たない名前(fudge
モジュールが何をするかわかりますか?)、ドキュメントがないもの、テストがないもの、ソースコードコメントがないもの、理解し難い関数名を持つものなどがあります。
多くのケースでは、アクティブなメンテナはいません。もしモジュールの質問に答えたりモジュールの機能を説明したりできる人がいなければ、ドキュメントがないことと相まって、モジュールはエイリアンのアーティファクトとなり、使い物にならず理解もできないものになるでしょう。
ドキュメントがあるモジュールの場合、その品質はどれくらいのもでしょうか?"16進数で数値をソートする"
という 1 行の説明だけかもしれません。あるいは、サンプルコードのスニペットだけかもしれません。どちらも何もないケースと比べれば進歩と言えますが、現代のモジュールユーザーに、実際にどのように動作するのかを理解するためにソースコードを掘り下げるという最悪のシナリオをもたらすこともあります。優れたドキュメントを書くことは、あなたのモジュールを十分に抽象化する説明を行うことで、ユーザーをソースコードから 遠ざける ことなのです。
Node は”広大な”エコシステムで、ひとつのことに特化し、互いに独立した、非常にたくさんのモジュールで構成されています。例外はありますが、こうした小さな領地はあっても、1 点に特化した市民たちが、その数の多さから Node 王国を真に支配しています。
このような状況では当然の帰結ですが、欲しいものを正確に実現する 質の高い モジュールを見つけるのは難しいでしょう。
これで問題ありません。本当に。参入のハードルの低さと検索性の低さという問題は、一部の特権階級しか参加できない文化の問題よりも、非常に良いことです。
加えて、検索性の低さは、結果的に、対処しやすいものです。
Node コミュニティは様々な方法で検索性の低さに対応してきました。
ベテランの Node 開発者が結束して良質なモジュールのキュレーションリストを作成しました。開発者たちは長年にわたって何百ものモジュールを調査し、それぞれのカテゴリーで最高のモジュールを Node の初心者のために公開しています。これはまた、信頼できるコミュニティメンバーによって、有用だとみなされた新しいモジュールの RSS フィードやメーリングリストの形式をとることもあるかもしれません。
ソーシャルグラフというアイデアはnode-modules.comの作成に拍車をかけました。この npm 検索代替ツールはあなたの GitHub のソーシャルグラフを活用して、あなたの友人が好きなモジュールや作成したモジュールを見つけることができるのです。
もちろん、npm 備え付きの検索機能もあります。安全で一般的な選択肢であり、新しい開発者のためにいつも開かれています。
どのようなアプローチをとろうとも、モジュールユーザーがnpmjs.orgやgithub.comなどで検索しても、ユーザーは最終的にはあなたの README と正面から向き合うことになるわけです。ユーザーは必然的にここにたどり着くわけですから、彼らの第一印象を最大限に良くするために何ができるでしょうか?
README は、モジュールのユーザーにとって、最初の、そしておそらく唯一の、あなたのモジュールに関する情報です。ユーザーは自分のニーズを満たすモジュールを求めているので、あなたは自身のモジュールがどのようなニーズを満たし、どのように効果的にニーズを満たすかを正確に説明する必要があります。
あなたの仕事は
- 文脈を含めて、モジュールが何であるかを伝える
- 実際にどのように見えるかを見せる
- 使い方を紹介する
- その他の関連する内容を伝える
これが あなたの 仕事です。自分の作品が粗悪なモジュールの海の中で輝く宝石であることを証明するのは、モジュール作成者次第です。多くの開発者の目は、何よりも先に README に向くので、README の品質があなたの作品の評価基準になるのです。
README がないのは大きな危険信号ですが、README の長さが品質の高さを示すというものではありません。理想的な README はこれ以上短くならないほどに短いものです。詳細なドキュメントは別のページにして、README は簡潔にしましょう。
歴史を学ばない者は、同じ過ちを繰り返すと言われます。開発者がドキュメントを書くようになってから、かなりの年月が経ちました。Node が登場する前に、人々が何をしていたのか少し振り返ってみる価値はあるでしょう。
Perl は、否定されることもありますが、ある意味では Node の精神的な祖父母にあたります。どちらも高水準のスクリプト言語で、多くの UNIX イディオムを採用し、インターネットの発展を牽引し、モジュールの広範なエコシステムを備えていることを特徴としています。
Perl コミュニティのmonksたちは、質の高い READMEを書くことにかけては実に多くの経験を積んでいることで知られています。CPAN は、質の高い水準のドキュメントを書いたコミュニティについてもっと学ぶための素晴らしいリソースです。
README がなければ、ユーザーはモジュールを理解するためにコードを掘り下げる必要があります。
この問題に関しては、Perl monks は知恵を共有してくれています:
ユーザーがコードを見ることなく、あなたのモジュールを使用できていれば、あなたのドキュメントは完璧だということです。これは非常に重要です。ドキュメントが完璧であれば、モジュールの文書化されたインターフェース部分と内部実装(心臓部)を分離することが可能になります。これは、インターフェースが同じである限り、モジュール内部を自由に変更できることを意味するので、良いことです。
モジュールが何をするのかを定義するのは、コードではなく、ドキュメントであることを覚えておいてください。 -- Ken Williams
README があれば、モジュールユーザーはそれを読んで自身のニーズに合致しているかどうかを確かめなければなりません。これは本質的には、開発者の脳内で解かれる一連のパターンマッチング問題となり、一歩ずつモジュールの詳細について深く掘り下げていきます。
たとえば、2D 衝突検出モジュールを探していて、collide-2d-aabb-aabb
に辿り着いたとします。私は、このモジュールを上から下まで調べ始めました:
-
名前 -- 自明の名前がベスト。
collide-2d-aabb-aabb
は期待できそうですが、これは私が”aabb”が何かを知っていることを前提としています。もし名前があまりにも漠然としていたり無関係に思えたら、他のモジュールに移るかもしれません。 -
ワンライナー -- モジュールを説明するワンライナーを持っていると、モジュールが何をするのか少しだけ詳しく知りたい時に便利です。
collide-2d-aabb-aabb
は、Determines whether a moving axis-aligned bounding box (AABB) collides with other AABBs.
素晴らしい。AABB とは何か、モジュールが何をするか定義しています。では、どれくらい私のコードにうまく組み込めるでしょうか:
-
使い方 -- API ドキュメントを掘り下げ始めるよりも、モジュールが実際にどのように見えるかを確認するのは良いアイデアです。サンプルの JS が求めているスタイルや解決したい問題にマッチしているかどうか判断できるからです。Promise やコールバックや ES6 といったものに対して、多くの人が異なる意見を持っていることでしょう。もし、要求を満たしてくれるなら、私はさらに詳細に進むことができます。
-
API -- このモジュールの名前、説明、そして使い方すべて魅力的に思えます。ここまでで、私にとってはこのモジュールを使う可能性が非常に高いです。API をざっと見て、私が必要とすることを正確に行い、私のコードベースに正確に組み入れることが可能であることを確認する必要があります。API のセクションは、そのモジュールのオブジェクトと関数、シグネチャ、戻り値の型、コールバック、イベントなどを詳しく説明する必要があります。型が明らかでない場合は、それも含めるべきです。注意書きも明確にすべきでしょう。
-
インストール方法 -- ここまで読んだら、このモジュールを使ってみようという気になります。もし標準的でないインストール方法があればここに書くべきですが、通常の
npm install
であったとしても、それについての言及が欲しいところです。npmjs.org へのリンクとインストールコマンドを書いてあげることで、Node の新しいユーザー は、Node モジュールがどのように動作するのかの理解することができます。 -
ライセンス -- ほとんどのモジュールはこれを一番下に置いていますが、実はもっと上にあったほうが良いかもしれません。あなたの仕事に不適切なライセンスを持つモジュールは、なるべく早くに排除したいでしょう。私は一般に MIT/BSD/X11/ISC 風のライセンスにこだわります。もしパーミッシブライセンスではないライセンスなら、混乱を避けるために一番上に貼り付けてください。
上記の順序は何もランダムに選んだわけではありません。
モジュールのユーザーはたくさんのモジュールを使用し、そして多くのモジュールを調べる必要があります。
何百ものモジュールを見ていると、予測可能なパターンに対して精神的な安定感を感じ始めます。
また、どのような情報が欲しいのか、どのような危険信号があればモジュールは不適合だと素早く判断できるのか、自分なりのヒューリスティックを構築し始めるのです。
したがって、README には次のようなものがあることが望ましいと言えます:
- 予測可能なフォーマットであること
- 特定の重要な要素が存在すること
必ずしも 上記の フォーマットを使う必要はありませんが、ユーザーの貴重な認知サイクルの無駄を省くために、一貫性を保たせるようにしましょう。
ここで紹介する順序は、”コグニティブ・ファネリング”と呼ばれ、漏斗を直立したイメージで、最も広い端には、最も一般的な情報が含まれています。漏斗の奥に進むほど、より具体的になり、あなたの作品に興味を持ち、その奥に到達した読者だけに適切な詳細があります。最後に、一番下には、作品のより深い文脈(背景、クレジット、参考文献など)に興味を持った人たちだけのために、そうした詳細を表示することができます。
今回もまた、Perl monks がこのテーマについて知恵を共有してくれています:
Perl モジュールのドキュメントは一般的にあまり詳細でないものから、より詳細なものまであります。SYNOPSIS セクションには最小限の使用例(おそらく 1 行程度のコードで、例外やほとんどのユーザーが必要としないものは省略してください。)を記載し、DESCRIPTION には大まかに、通常は数段落でモジュールについて記述し、モジュールのルーチンやメソッドの詳細、長めのコード例、その他の深い内容については以降のセクションで説明すべきです。
理想としては、あなたのモジュールについて少し知っている人が、”page down”キーを押すことなく、記憶を更新できるようにすることです。読者がこのドキュメントを読み進めるにつれて、徐々に多くの知識を得ることができるはずです。 --
perlmodstyle
より
素晴らしいことに、上記の重要な要素の順番は、誰かが「ショート」して、どれだけ早くモジュールを放棄させるかによって決定されています。
暗い話に聞こえますよね。でも考えてみてください。利他主義を念頭においた場合、あなたの仕事は、あなたの作品を「売り込む」こと(たとえばダウンロード数やユーザー数を最大化させること)ではありません。あなたの作品が何をするものなのかできる限り客観的に評価させ、それが彼らのニーズを満たしているかどうかを判断してもらうことです。
この考え方は、万人に受けるものではありません。自身のエゴは抑えて、作品になるべく語らせる必要があります。あなたの唯一の仕事は、その作品の約束事をできるだけ簡潔に説明することです。そうすれば、モジュールのユーザーはあなたの作品がニーズにマッチした時に使用するか、あるいは他の作品を探すかすることができます。
さあ、勇敢なるモジュール探索者よ、優れたドキュメントによって、あなたの作品を発見しやすく、使いやすくしてください。
本記事のキーポイントの他にも、README の品質の水準をぐっと高め、他の人にとっての有用性を最大化するために、従うことができる(あるいは従わなくても良い)プラクティスが存在します。
-
あなたのモジュールが、重要だがあまり知られていない抽象概念や他のエコシステムに依存している場合、背景セクションを記載することを検討しましょう。
bisecting-between
の関数は、その名前からすぐに分かるようなものではないので、詳細な 背景 セクションを設けて、それを使って理解するために必要な大きな概念や抽象概念を定義しリンクしています。また、同様のモジュールがすでに npm に存在する場合、このモジュールを制作した動機を説明するのにも最適な場所です。 -
積極的なリンク化!他のモジュール、アイデア、人について話す場合は、訪問者がより簡単にあなたのモジュールとモジュールのもとになったアイデアを理解できるように、リファレンスをリンクにしましょう。他の何にも依存しないモジュールはほとんどありません。すべてモジュールは他のモジュールに由来します。ユーザーがあなたのモジュールの歴史とインスピレーションをたどるのを助けることは、とても大切なことなのです。
-
引数や戻り値のパラメータが明確でない場合は、その情報を含めること。可能な限り慣例に従うこと(
cb
はコールバック関数、num
はNumber
を意味する、など) -
使い方にあるサンプルコードを、リポジトリのファイルとして含めること -- 例:
example.js
。ユーザーがリポジトリをクローンしたときに、README に記載されているコードを実際に実行できるならば、それは素晴らしいことです。 -
バッジの使用には慎重を期してください。濫用される恐れがあります。また、些細な議論や終わりのない議論の温床になる可能性もあります。バッジは README の視覚的なノイズになることに加え、一般的にユーザーがオンラインのブラウザであなたのマークダウンファイルを読んでいる場合にのみ機能します。画像はほとんどがインターネット上のどこかでホストされているからです。それぞれのバッジについて考慮してみましょう: ”このバッジは README の一般的な読者に、どのような価値を提供しているのだろうか?”。ビルド/テストのステータスを表示する CI バッジはありますか?このステータスは、メンテナにメールを送ったり自動的に Issue を作成したりするほうが、重要な関係者は気付きやすいはずです。README に記載されている情報の読者のことを常に考え、その情報が意図した読者にもっとよく届くようなフローを作れないか自問しましょう。
-
API のフォーマットは、些細な議論の的になり得ます。最も分かりやすいと思われるフォーマットを使ってください。ただし、そのフォーマットが重要な細部を記述できていることを確認してください。
a. どのパラメータが任意なのか、そしてそのデフォルト値
b. 慣例から明らかでない場合の型情報
c.
opts
オブジェクトパラメータがある場合、受け取るすべてのキーと値d. API の関数の使い方が明白でない、あるいは使い方セクションで完全にカバーできていない場合は、小さなサンプルであっても提供することをためらわないこと。ただし、これはその関数が複雑すぎるというしるしでもあり、リファクタリングやより小さな関数への分割、あるいは完全に削除する必要があるということでもあります。
e. 専門用語は積極的にリンク化する!マークダウンファイルでは、脚注をドキュメントの一番下に記載しておくと、ドキュメント中で何度でも参照しやすくなります。API のフォーマットに関する私の個人的な好みについては、こちらを参照してください。
-
モジュールがステートレス関数の小さなコレクションである場合、関数の呼び出しと結果のNode の REPL セッションとして使い方セクションを記載すれば、実行可能なソースコードファイルよりも分かりやすく使い方を伝えることができるかもしれません。
-
モジュールがプログラム的な API の代わりに(あるいはそれに加えて)CLI(コマンドラインインターフェース)を提供しているなら、コマンドの呼び出しとその結果として、使用例を示してください。ファイルを作成または変更するようならば、
cat
コマンドで変更前と変更後の状態を示しましょう。 -
モジュールを探している人に見つけてもらうために、
package.json
のキーワードを使うことを忘れないでください。 -
API を変更すればするほど、ドキュメントの更新に労力を割かなければならなくなります。つまり、早い段階で、API を小さく、具体的に定義しておくべきだということです。要件は時間とともに変化するものですが、モジュールの API を事前に想定するのではなく、モジュールセットという、一段上の抽象化されたレイヤーを作りましょう。もし要件が変わって「特定のことをする」だけでなくなったら、必要なことをする新しいモジュールを書けば良いのです。「特定のことをする」モジュールは、npm エコシステムにとって有効かつ貴重なモデルであり続け、軌道修正する際には、あるモジュールを別のモジュールに置き換えるという単純な作業以外には何もコストはかかりません。
-
最後に、バージョン管理されているリポジトリとその中の README は、リポジトリのホストやハイパーリンク先(特に画像)よりも長く存続することは覚えておいてください。そのため、将来のユーザーがあなたの作品を理解するために不可欠なものは、すべて埋め込んでおくようにしてください。
偶然ではありませんが、これはcommon-readmeという README のガイドラインと便利なコマンドラインジェネレータでも使われている形式です。もしこの記事に書かれていることが気に入ったら、common-readme
を使えば README を書く時間を節約できるかもしれません。この形式を使っている実際のモジュールの例も紹介されています。
また、standard-readmeもおすすめです。こちらはより構造化されていて、リント可能な一般的な README フォーマットです。
理論は良いとして、優れた README というものは具体的にどのようなものでしょうか?ここでは、私がこの記事の原則をよく体現していると思うものをいくつか紹介します:
- https://github.com/noffle/ice-box
- https://github.com/substack/quote-stream
- https://github.com/feross/bittorrent-dht
- https://github.com/mikolalysenko/box-intersect
- https://github.com/freeman-lab/pixel-grid
- https://github.com/mafintosh/torrent-stream
- https://github.com/pull-stream/pull-stream
- https://github.com/substack/tape
- https://github.com/yoshuawuyts/vmd
README の完成度を測るのに便利なチェックリスト:
- モジュールの目的を説明するワンライナー
- 必要な背景情報やリンク
- 見慣れない用語の、有益なリソースへのリンク
- 明確かつ 実行可能な 使用例
- インストール方法
- 豊富な API ドキュメント
- コグニティブ・ファネリングの適用
- 注意点・制限事項の事前説明
- 重要な情報の説明を画像に頼らない
- ライセンス
著者はnoffleです。blog、tweet、hackなどで知られています。
この小さなプロジェクトは、5 月にベルリンの squatconf で始まりました。そこで私は Perl monks がどのようにドキュメントを書いているかを掘り下げていて、また Node エコシステムの README の状況を嘆いていました。これがcommon-readmeを作る動機になりました。"README Tips"セクションは、ヒントであふれるほどだったので、README の書き方について記事にまとめると役に立つと判断しました。こうして、Art of README が誕生したのです!
私の連絡先は、[email protected]
または Freenode IRC の#eight45
です。
-
ありがとう、 Sixes666!
-
The Jargon Fileを参照してください。しかし、現在のほとんどのシステムでは、大文字を小文字の前にソートすることはないため、この慣習の有用性は大文字の視覚的なインパクトだけにとどまります。
このアイデアを実現させ、書き始めるために必要な励ましをくれた@mafintoshと@ferossに心からの感謝を!
間違いに気付いて PR を送ってくれた以下の素晴らしい読者に感謝します ❤️ :
- @ungoldman
- @boidolr
- @imjoehaines
- @radarhere
- @joshmanders
- @ddbeck
- @RichardLitt
- @StevenMaude
- @KrishMunot
- @chesterhow
- @sjsyrek
- @thenickcox
Art of README を中国語に翻訳してくださった@qihaiyanに感謝します!また下記のユーザーにも貢献していただきました:
- @BrettDong 中国語版の句読点の修正について
- @Alex-fun
- @HmyBmny
- @vra
Art of README をブラジルのポルトガル語に翻訳してくださった@lennonjesusに感謝します!また下記のユーザーにも貢献していただきました:
Art of README をスペイン語に翻訳してくださった@jabiinfanteに感謝します!
Art of README をドイツ語に翻訳してくださった@Ryuno-Kiに感謝します!また下記のユーザーにも貢献していただきました:
Art of README をフランス語に翻訳してくださった@Manfred Madelaineと@Ruben Madelaineに感謝します!
最後に、たくさんの感想をありがとうございます!意見があればIssueに共有してください。