ドキュメンテーションはソフトウェア開発の重要な部分を占めているが、見過ごされることが多い
「ドキュメンテーション」(Wikipedia)
ドキュメンテーションの重要性はプログラマーなら誰もが認識していて、他人の書いたライブラリに必要十分なドキュメンテーションがされていないと「ふざけんなよ!」と大抵はブチ切れます。
最近はGitHubがReadme.mdを自動で綺麗に表示してくれますから、Readme.mdに多少の使い方を書くケースは増えているようです。
素晴らしい。
しかしそこに書かれている内容は実のところ断片的かつ限定的な情報で、少し応用したりちょっと拡張したい、と思った時には使い物にならないことがほとんどです。
「ソースコードは公開されているんだから読めばわかる」と言われても、赤の他人が作った見知らぬライブラリの全体概要から個別仕様まで把握するのはいくら見通しの良いコードでもそれなりに手間のかかるものです。
その手間をかける価値のあるものかどうかもわからない状況でそこまで踏み込めるか、といえば誰だって躊躇わざるをえません。
さて。
ではあなたが書いてGitHubで公開しているちょっとしたライブラリに丁寧なドキュメントはついていますか?
Readme.md書いただけだったりしませんか?
私はReadme.md書いただけで満足します。
なぜあなたも私もドキュメンテーションできないのか
Qiitaは『プログラマの技術情報共有サービス』だそうですから、もちろん『ソフトウェア開発の重要な部分を占めている』ドキュメンテーションについてもたくさんの情報があるはずです。
実際、検索してみると、その数の豊富さに泣けてきます。
なぜ私たちはドキュメンテーションができないのでしょうか。
なぜ私たちはドキュメンテーションから目を背けるのでしょうか。
- 面倒だから
- 手間がかかるから
- 面白くないから
- やる気がわかないから
10個考えるのが面倒になったのでこれで打ち切りますが、単に手間がかかる&楽しくない、という話です。
なぜ手間がかかるのか
わかりきった話ですが、あえて書くと次のような感じです。
# ファイルを読み込む
# @param [String] path ファイルパス
# @param [Hash] opts オプション
# @option opts [String] :encoding 文字エンコード
def load(path, encoding: 'utf8')
...
end
# ファイルを保存する
# @param [String] path ファイルパス
# @param [Hash] opts オプション
# @option opts [String] :encoding 文字エンコード
def save(path, encoding: 'utf8')
...
end
ほとんど同じ内容を2回繰り返しています。
正直、どこで定義されていようがpathという名前の引数がファイルパス以外の意味で使われることは無いでしょう。
(XMLライブラリなどそれ以外の意味でpathを使うケースはもちろんあるでしょうが、その場合はその意味でライブラリ内は統一されているはず)
そしてpathが出てくるたびに@param [String] path ファイルパス
が繰り返されるわけです。どうやって繰り返すのかといえば、それはもちろんコピペであり、これは私たちハッカーが最も憎むべき敵です。
仇敵に身を委ねなければならない屈辱が何度も繰り返された結果は快楽を感じ始めるか辟易とするかのどちらかであり、なぜかハッカーは前者に至ることができません。
(前者は狂ったようにコピペを繰り返すようになりますから、それはもはやハッカーとは呼べない、とも言えます)
ちゃんと設計されていれば同じ引数名がメソッドによって違う型や違う意味で使われるケースというのはそれほどないでしょう。
これを自動解決するため、私は自分でその辺を適当にやってくれるドキュメンテーションツールを自作するに至りましたが、もっとメジャーなドキュメンテーションツールをforkして機能追加すると多くの人がきっと幸せになれることでしょう。
しかしやはり楽しくない
本稿の本題はこちらです。
苦痛の原因は上述のコピペ地獄であると考え、自作のツールで私はそれを解消しました。
その結果は、 やっぱり楽しくなかった でした。
コピペが一因であることは間違いないでしょう。
しかしそれが(なにかしらのツールで)解決できたとしても、ドキュメンテーションは苦痛なものであり、その原因と解決法をここで共有したいと思います。
精神衛生の重要性
例えば次のように書いたとします。
(Ruby公式リファレンスから抜粋)
# nth番目の要素をvalに設定します。
def []=(nth, val)
# cntで指定したインデックスの要素が先頭になるように自身の順番を変更します。
def rotate!(cnt=1) -> self
他人が書いた文章なんてだいたい真面目に読みませんから気にならない人もいると思いますが、これを自分で書いて読み直すと「ん?」と思うはずです。
上と下のメソッドは、nthとcntで別名にする必要があるのでしょうか。
下のメソッドの記述内容は「nth番目の要素が先頭になるように」ではダメなのでしょうか。
上では「設定します」と書かれていますが、下では「変更します」と書かれていて、いったい何が違うのでしょうか。
このドキュメントを書いた本人であれば両者が違う意図なのか同じ意図なのかわかります。
そして同じ意図なら同じ表記にしないと誤解を招くかもしれないと気になります。
気になりませんか?
私、気になります。
(略)
気にならない人もいるでしょうが、私は気になります。
私が気になると言うことは、同じように気にする人もきっといるはずです。
まとめて書いていると意識しなくても揃うものですが、日を跨いで書くと表記が不統一になることは珍しくありません。
そしてこういった不統一は書いている途中は気にならず、あとでまとめて見返したときに初めて気が付き、結果として最初から読み直しながら修正する羽目になります。
ただでさえ面白くもないドキュメンテーションを2度も3度も読み返しながらやる。
やればやるほど正気度が失われていきます。
解決策
文芸的プログラミングを試みる
あとになってからのドキュメンテーションはマジでヤバい、とクヌース先生もおっしゃっています。
doxygenでもjsdocでもyardでも何でも構いませんが、文芸的プログラミングとしてのスタイルを採ることで楽になることは多いでしょう。
そういった手癖を付け、適切にツールを活用することが大切なのではないでしょうか。
り、りろんはしってる。
私たちが書かねばならないのは今書いている自分が読んで分かるドキュメントではなく、それを初めて触る誰かや3年後の自分が違和感なく読めるドキュメントです。
ツールでHTMLの出力は容易に出来ますが、元となる文章を書くのは人間であり、そこで「なるべく違和感を与えないドキュメントを一発で書く」ための工夫がプラスアルファとして必要だと考えます。
文体を最初に決めておく
最近はオートコンプリートも高度化していますから適当に書いてもなんとかなることも多いでしょうに、命名規則はみんな気にします。
Google Style Guideとか見るの大好きですよね?
私は大好きです。
なぜかといえば書いていて不揃いだと気になるからです。
揃っていると気持ちがいいからというより、揃っていないと気持ち悪いからです。
ドキュメンテーションも同じです。
用いる日本語の基本方針をどこかにまとめて書いておくことで、昨日の自分と今日の自分そして明日の自分で統一が図れます。
考慮するべきいくつかの点
- 文体の統一
- 「です・ます」なのか「だ・である」なのか
- 句読点の統一
- 「。、」なのか「.,」なのか
-
文末に句点を付けるのか付けないのか
- 句読点は一切付けない、という選択肢はまずないでしょうが、
句点を必ず最後に付ける、というスタイルを採る場合、
例えば「ファイル名」という名詞だけでも句点を付けるのかは
最初によく考えて決めた方がいいでしょう。
あとで変えたいと思った時に機械的な置換が困難なため、
全部目視で確認する羽目になります。
- 句読点は一切付けない、という選択肢はまずないでしょうが、
- 用語の統一
- 例:
- 「初期値」ではなく「デフォルト値」
- 「設定します」ではなく「変更します」
- 返り値は「返します」
- コンストラクタは「生成して返します」
- bool値を返すときは「~の場合に真を返します」
- 例:
- 主語の統一
- 「ユーザ」を主語にするか「メソッド」を主語にするか
- 用語の統一にも影響しますが、
ユーザを主語にするならメソッドの返り値は「取得します」、
メソッドを主語にするなら「返します」
とするのが自然でしょう。
説明文を記述するとき、主語が何かを統一することで能動態/受動態の混濁を減らせます。
- 用語の統一にも影響しますが、
- 説明文に定義された引数名はなるべく含めない
* 「nth番目の要素をvalに設定します」のような表記を許容するかどうか、という点です。
変数名のリファクタリング機能が高度に機能してくれる環境であればどう書こうが自由ですが、そうではない環境において例えばnthをindexに変えた場合、記述されたドキュメントにおいてもnthをindexに変える必要が生じます。
宣言された引数名と内部で用いられている引数名が違えば普通エラーになるのでリリース前に気が付けますが、この手のドキュメントに書かれたものと引数に書かれたものが違ってしまった場合、一度見逃すとまず気が付けません。
従って、説明文中に定義された引数名をなるべく記述しない、という手法を検討する必要があります。
- 「ユーザ」を主語にするか「メソッド」を主語にするか
記述する範囲を明確にする
「書かなきゃいけない範囲が たくさん ある」はそれだけで精神衛生を悪化させます。
ドキュメンテーションが必要な範囲はどこかを整理しましょう。
自分が今どこまでドキュメンテーションできたのか。
あといくつ書けば終わりなのか。
終わりが見えない、というのは本当につらいものです(例:デスマ)。
最初に終わりがどこなのか、本当にそれだけやる必要があるのか、とりあえず使うために必要なドキュメンテーションはどこからどこまでなのかを明確にしておくことで、多少は気が楽になります。
なぜドキュメンテーションをするのか考える
ドキュメントが無いと、誰かが使おうとしたときに困ります。
あなたが苦労してドキュメンテーションをすることで、誰かが使おうとしたときに楽になります。
お前の苦しみが誰かの喜びにかわるんだ。
やり遂げたまえ。
「文豪ボースカ」(大槻ケンヂ)
最後に
私たちはドキュメントを読むことでプログラム言語やライブラリの仕様を把握しており、その重要性をよく理解しているはずで、そしてドキュメンテーションツールは山ほど世の中にあります。
しかし世の中に数多とある個人が趣味で作ったちょっとしたライブラリは、だいたい「仕様はソースコード読んでください」です。
便利なツールがあることはそのライブラリの作者もきっと知っています。使い方だって知らないわけではないでしょう。
ツールが知られていないからではなく、ドキュメンテーションを完遂するための技術やノウハウがどうも足りてないんじゃないのか、というのが本稿の投稿意図です。
ちなみにRubyのドキュメンテーションがどうなされているか、についてはちょっとるりまでも更新してみようかが参考になります。