はじめに
自明なコメントは書くな、とよく言われますが、どこまでが自明と呼べるのかは、人によって異なります。加えて、自分で設計して自分でコードを書いている以上、コメントを書く側の方が、自明と思える範囲(というよりコードに対する暗黙知の量なのですが)は広くなるものです。
従って、自分で自明と思っている事でも、保守や機能拡張で後からコードを読む側には重要な事というのは結構あります。
が、コメントを書き慣れない人程、そういった、後から読む人の視点に欠けているように思えます。
なので、他人の書いたコードを保守する仕事ばかりやってきた自分が、こういうのがあると嬉しい、という視点でコツをまとめて見ました。
クラスヘッダやメソッドヘッダに欲しい情報
クラスやメソッドの概要を一行で
実は「自明なので要らない」と言われそうな物です。なので一行でよいです。
しかし、読む側にとっては、最初にクラスやメソッドの全体像が分かることで、以後に出てくるメンバ変数やローカル変数、メンバメソッドなどが、何のために、どういう使われ方を想定して書かれているのかをイメージしやすくする効果があります。
物事を説明する時に概要から詳細に、というセオリーがありますが、それと同じです。
また、このことは、説明する側が説明する内容をまとめる時、つまり、コメントを書く側が、何を書くべきかを考える時にも有効です。
最初の一行に、自明であっても概要をあらわす一文があることで、その後に本当に説明すべき内容を書き出しやすくなるのです。コメントを書くことへの心理的なハードルが下がると言ってもよいです。
クラスの状態遷移やメソッドの実行条件に関する仕様
- 「シングルトンであるので、スレッドセーフ時に注意」
- 「メッセージ管理をシンプルにするために、通信1回ごとに生成→破棄するように使う」
- 「コンストラクタの他にsetHoge()を呼ばないと他のメソッドが機能しない(初期化が完了しない)」
- 「終了時に先にreleaseHogeを呼ぶ事」
といったような内容のコメントのことです。
もちろん、こういった実装は、設計で回避できるならそれに越した事はありませんが、機能拡張が簡単に実現するために例外パス的に追加、というような形で実装される事もありますので、ケースとしてはそれなりに見かけます。
しかし、意外とこういう情報をヘッダに書いているケースは多くありません。
クラスを実装した人にとっては自明な情報だからでしょうが、書いた当人以外は、コードを読まないと分からないことの例、と言えます。
メンバ変数や、メソッドの引数の説明に欲しい情報
変数の役割を簡潔に
「クラスやメソッドの概要を一行で」と、内容的にはほぼ同じです。
が、変数名からすぐわかる情報以外を書くとなると、案外難しい項目です。
難しいので書かない、という事態はできれば避けたい所です。なので、まずは概要としてとりあえず書いて、その上で、以下に続く情報があればよいと思います。
変数の値の有効範囲と単位系
意外と書かれてないことが多いものです。
変数型はint型だけども実際に入力可能な範囲は1~100までしかないなら、それは明記されるべきです。
また、updateTimeといった変数があった時、有効な単位系が時分秒のどこまでなのか、ローカルタイムは意識しているのか、全世界共通にするためUTCで統一しているのか、など、変数の値の有効範囲については結構な量の(暗黙的な)情報があるはずです。
逆に、変数型がenum型であるならば、enum定義でその説明が書かれるべきなので、変数での説明はシンプルでよいでしょう。
メンバ変数の初期化や変更タイミング
上に上げた「クラスのライフサイクルや、状態遷移に関する仕様」とも関連する情報です。
コンストラクタ完了後に、別途初期化が必要な変数は、変数側にも一言あると良いでしょう。
クラスヘッダに書かれるものは、クラスの概要としての情報なので、説明の観点が異なるのです。
引数の方向
C/C++など一部の言語系限定の話ですが、メソッドにポインタ変数を引数として渡す場合、それがメソッドへのインプットなのか、メソッドの処理結果を格納するためのものなのか、明示するということです。
一方で、例えばC#では、メソッド定義に明示的にoutを付ける事を要求されるので不要と言えます。
その他のテクニック
ブロックを明示してブロックコメントをつける
ブロックとは、メソッドの内側で、処理の区切り事に空行を入れて、処理の区切りを明示した単位のことです。
その上で、ブロックごとに何をしている、というコメントがあると、処理の詳細を忘れかけた頃に見直すとき、非常に思い出すのが早くなります。
特に市場障害で対応しているときなどは、いちいち実装を読んで確認をしている時間さえ惜しい時があります。
そういう時に、ここまでは関係なさそう、と実装を読み飛ばせるのは、対応時間の短縮に非常に効果があります。
「分かりやすい名前」の限界
変数名やクラス名に分かりやすい名前を付けるべきであるのは当然ですが、限界もあります。
自分がどれだけ分かりやすい名前を付けたつもりでも、後から読む他人が、その名前を構成する単語1つ1つを自分と同じように訳すとは限りません。
例えば、ユーザー選択可能なパラメータをダイアル形のGUIで表示している時、それに対応するデータクラスで、「setCurrent」「getCurrent」と書かれたメソッドを見た事があります。
currentというからには現在の値を指しているのでしょう。それは分かります。
が、問題は、これがダイアルのインデックスなのか、ダイアルに表示されている値なのか分からず、実装を読むハメになりました。
これは、ありていに言えば命名が悪い(曖昧な単語の使用)のですが、これを書いた人は、おそらく名前から判断できると考えたのでしょう。そのメソッドにもクラスにも、説明のコメントはありませんでした。
これは、相手が自分と同じように訳するはずだ、という錯覚から生まれた「わかりにくい」の例です。
コメントの記述をパターン化する
コメントを書くのに苦手意識がある人は、「~なので~する」という感じに、文章をテンプレ化すると良いと思います。
例えば、「後で同じ計算をするので、中間値を保存して計算量を下げる」などのような感じです。
「~なので」の部分が明確に意図を伝えるものになるので、コメントとして価値が出ます。
「~する」の部分は、明示的なら「こうする」でも構いません。
テンプレ化することで、コメント記述の心理的なハードルが下がり、気にならなくなります。
最後に
コメントというのは、防波堤のようなものだと思います。
開発中は実際に役に立ちません。そのコードを、今設計や実装している要員にとっては既知のことばかりだからです。
しかし、1年後、わずかな保守要員しか残らなくなった時に市場障害でも出ようものなら、ドキュメントもコメントもない、は大惨事に直結します。それを防ぐためのコメント(ひいては設計書などのドキュメント全般)だと思えるからこそ、防波堤のようなもの、です。
よく、コメントのメンテの手間をかけるなら実装を進めたいというような意見がありますが、比較対象を間違えています。
コメントのメンテコストと比較されるべきは、将来、市場障害が発生した場合の損害です。
なので、保守する必要がないとか、最初の実装者が最後までメンテするのであれば、確かにコメントなど不要です。
また、間違ったコメントが誤解を拡大するようなリスクも、現実にはあまりありません。
なぜなら、仕様書や設計書があるならそれが、ないなら、何らかの手段で仕様とその変更を開発メンバー間で共有するプロセスがあるはずですから、そちらを基本正しいと考える事で、コメントの間違いをベリファイできます。
加えて、仕様書はなかなかメンテされなくても、毎日見るソースならば、コメントのミスは気がついた時にメンテできます。
コメントが動作に影響を与えるわけでもありませんし。
その上で、コードの内容を分かっている要員がコメントを書いたり保守する時間より、分かってない要員がドキュメントやコメントなしで解析する時間の方が、圧倒的に長い時間を要するという事実を考えれば、コメントを書かない理由はないと思います。
ということで、「後の人のために」コメントを残す習慣がもう少し根付いて欲しいと願っています。