プログラムに対する適切なコメント付けについて考えてる
上記記事を読んだ。 「コメントを入れるか入れないか」 について言及されていて、ちょうど最近、人から 「nobuoka はコメントを書きすぎだと思う」 と指摘されたところだったので、『Code Complete』 に興味がわいた。 『Code Complete』 はそのうち読むとして、そういう本を読んでみる前に自分のコメントについて振り返ってみようと思う。
職業プログラマーなら必ず読むべき「Code Complete」 - $shibayu36->blog;コメントを入れるか入れないか
- これまでのコメント論をきちんと表しており、この部分は本当におもしろかった
- 結論としては
- ややこしいコードの意味をコメントで説明するくらいならコードを綺麗にすべきだが、コードよりも抽象的レベルで説明するコメントは絶対に必要
- 特に複数人なら。一人でも未来の自分に向けて必要。
- しかし、コードを復唱するコメントは最悪である
- コメントの最適な数としては大体10ステートメントに1個くらいで、プログラムが最も明瞭になるという研究がある
なぜコメントを書くのか
私がコメントを書くのは、基本的には将来の自分や他人がそのコードを読むときに読みやすくなるように、という目的である。 これはおそらく大多数のプログラマがそうなのではないかと思う。
その目的部分ではみんな合意できると思うのだけれど、問題は 「どういうコメントがあると読みやすいと感じるのか」 あるいは 「読みにくいと感じるのか」 という部分はプログラマごとによって違うということだと思う。
なので、読み手として 「自分自身はどういう場合にコメントがあると嬉しいのか」 みたいなのを実例付きで書いてみる。
どういうコメントがあると嬉しいか
自分自身、どういうコメントがあると嬉しいと思っていて、実際にどういうコメントを書いているのか。
コードだけからは読み取れない 「意図」 を説明するコメント
例 1 のように、「なぜそういうことをするのか」 を説明するコメント。
なぜそうするのか、という意図はコードからは読み取れないわけなので、意図を説明するコメントに対して否定的になる人はほとんど居ないと思う。
クラスやメソッド、フィールドなどの説明をするコメント
例 2 のようにクラスの説明をしてたり、例 3 のようにメソッドとその引数などの説明をしてたり、例 4 のように変数の説明をしたりするコメント。 私はコードを読んで理解するのに結構時間がかかるので、こういうコメントがあると嬉しい。
- 例 2 : wscutils の info.vividcode.util.oauth.OAuthEncoder クラスの説明
- 例 3 : wscutils の info.vividcode.util.oauth.OAuthEncoder.encode メソッドの説明
- 例 4 : wscutils の info.vividcode.util.oauth.OAuthEncoder における静的プライベート変数 BS の説明
例 2 や例 4 に関しては 「そもそも名づけが糞である」 と思うし、例 2 だと本来は OAuth 1.0 の RFC の URL でも張っておくべきところだとも思うが、まあそれは今回は良いとしよう。
最近 「こういう説明は実装を読めばわかるから書かないでほしい。 実装を読むときの邪魔になる」 って言われて、そういう人もいるのかー、と思ったりした。 上の例は実装が簡単なのでまあコメントがなくても読むのにかかる時間はそんなに変わらないだろうけど、もうちょっと長かったり難しい処理をしているメソッドなどを読むことを考えると、私の場合はコメントがある方がより速くコードを読める *1 と思う。 少なくとも (読む必要がないコメントでも) 邪魔とは感じないかなー。 まあそこら辺は人それぞれなのかもしれない。
今回挙げた例だと仕様的な部分は全部クラス内に閉じているので、「encode メソッドによるパーセントエンコードの対象になるのは 'A'-'Z', 'a'-'z', '0'-'9', '-', '.', '_', '~' を除く全ての文字である」 ということはクラス内を全部調べればわかることではあるけど、encode メソッドを使いたいときにいちいちクラス内の実装を全部読みたいとは思わない。 それに動的型付けの言語だと、(コメントに書かれていないと) そのメソッドに渡されてくる引数の型さえも呼び出し側を見ないと全くわからない場合もあるわけで、「あるメソッドを使いたいと思った時に、引数に渡すべき型を知るためにそのメソッドを呼び出している別の箇所を調べる」 などをいうことをする必要がある。 個人的にはやりたくないなー。
まあ思想が統一されていないのは、コメントを付けるとか付けないというどちらの方針よりも良くないと思うので、複数人が関わるプロジェクトの場合はそのプロジェクトの指針に従うべきだと思ってる。
処理の塊を説明するコメント
例 5 の removeBackgroundImage メソッドの中のコメントに書いているように、「設定値を変更して保存する」 「見た目を更新する」 「ファイルを削除する」 という具合に、理想的にはそれぞれメソッドに切り出して抽象化すべきような内容を同じメソッドに書く場合などに、処理の塊が明示されるようにコメントを書くことがある。
「理想的にはメソッドに切り出して抽象化すべき」 と上に書いたが、実際のところ 2 行の処理をプライベートメソッドに切り出す必要性はないと思うので、こういうコメントを書いておく形が個人的には良いと思っている。 まあ今回の例だと 2 行の処理に対して 1 行のコメントを付けてるので、「こんなコメント書くな糞が」 と言われても仕方ないかなーという気はするし、個人的なプロジェクトの場合しかこういうことはしてないつもりではある。
TODO など
例 6 のように TODO などが書かれたコメント。
TODO とか FIXME とか XXX とか、そもそもそういうものを書かないで済むようにするのが理想ではあるけど、実際にはそういうのは残ってしまうので、コメントに明記しておくのが良い。 これについても 「意図」 のコメントと同じで否定的に思う人はほとんど居ないと思う。
ドキュメントなどへの誘導
例 7 や 8 のように、ドキュメントの URL などが書かれたコメント。
- 例 7 : MeteorLine の BackgroundImageManager クラスで WinJS.Class.mix を使っている場所から 「カスタム コントロールを構築」 のブログ記事への誘導
- 例 8 : MeteorLine の BackgroundImageManager クラスで Windows ストアアプリにファイル保存している場所からドキュメントへの誘導
自分が探すのに苦労したドキュメントなど、将来の自分がそのコードを読んでドキュメントを見たいと思った時に探すのに苦労すると考えられる場合は URL などを書いておく。 個人プロジェクトの場合はわりと気軽に使うけど、複数人が触るコードの場合は気軽には使わないようにしている。
利用者に対する注意など
例 9 のように 「このメソッドを使うときはこういうことに注意すること」 みたいなコメント。
パブリックなメソッドの場合はこういうコメントを書くべきではなくて、実装側で安全にしておくべき。 一方で、ある範囲内でしか使用されないプライベートなメソッドの場合は、その範囲内の実装者が気を付けられると考えられる場合はコメントに注意点を書いておいて、実装時に注意する、などすればよいと思う。 例えばクラス内にプライベートなメソッドとか。 例 9 の場合はクラス外に公開されているメソッドだけど、個人プロジェクトだし 「プロジェクト内にプライベートである」 と考えられるので、コメントを付けて注意喚起する程度で十分だと思って、そのようにした。
メソッドの実装者が知っておくべき仕様
例 10 の JSON における数値の表記形式の仕様が書かれたコメントのように、メソッドの仕様の説明ではなく、メソッド実装者が知っておくべき仕様を書いたもの。
RFC などの URL を張っておけばいいという話かもしれないけど、実装する立場の人間としてはそのメソッドに関する部分だけコメントで書かれていた方が嬉しい。 しかしその場合でも RFC などの URL は張っておくべき (少なくとも参照した仕様がなんであるかが明確にわかるようにすべき) だと思うので、上のコメントはその点では糞だと思う。
その他
大体そんな感じかなー。 あとは著作権表記をコメントに書いたり、Javadoc とかだとコードサンプルを書いたりすることもあるけど、それはコードとしてのコメントというよりはドキュメントとしてのコメントなのでその他扱いでいいような気がする。 他には、設計のことを書いたりすることはあるかなぁ、という程度か。
適切なコメントについて考えてる
今までコメントがなくて困ったことはあってもコメントがあって困ったことはなかったので、こないだ 「コメントがあると邪魔」 って言われて結構驚きがあった。 なので最近は適切なコメント量、あるいはコメントの種類について考えたりしてる。
shiba_yu36 さんの記事を読んだところ、『Code Complete』 には以下のように書かれてるらしいけど、詳細を知りたい感じだ。
- コードよりも抽象的レベルで説明するコメントは絶対に必要
- コードを復唱するコメントは最悪
自分のコメントはコードを復唱するもののつもりではないけど、実際には復唱するものに分類されるのかなー。 あるいは抽象化のレベルが適切でないとか。 うーん。
info.vividcode.util.json.JsonParser クラス は 2 年前に書いたコードで今見るとひどい感じの実装ではあるけど、コメント付けに関しては今の自分が見ても過不足ないと思う (が、逆にいえば実装をもうちょっとまともにすればコメントは減ると思う) ので、自分自身が自分自身のために書くコメントについてはちゃんとできてるかなーというのが今のところの実感としてある。 問題は複数人で触るコードだよなぁ。 他人のコードの読み書きについての経験は浅いので、そこら辺は経験を積むと同時に本を読んで勉強したいところ。
まあ何はともあれ 『Code Complete』 を読んで、それからまたこの記事に書いたことを振り返ってみよう。
Code Complete第2版〈上〉―完全なプログラミングを目指して
- 作者: スティーブマコネル,Steve McConnell,クイープ
- 出版社/メーカー: 日経BPソフトプレス
- 発売日: 2005/03
- メディア: 単行本
- 購入: 44人 クリック: 1,162回
- この商品を含むブログ (280件) を見る
Code Complete第2版〈下〉―完全なプログラミングを目指して
- 作者: スティーブマコネル,Steve McConnell,クイープ
- 出版社/メーカー: 日経BPソフトプレス
- 発売日: 2005/03
- メディア: 単行本
- 購入: 16人 クリック: 193回
- この商品を含むブログ (158件) を見る
*1:ここで言う 「コードを読む」 というのは、当該メソッドの実装を読む場合と当該メソッドを使用しているコードを読む場合の両方を含んでいる。 また、当該メソッドを初めて読む場合も、既にそのメソッドを知っており記憶がおぼろげながらに存在する場合も両方含んでいる。