コメントを書かないためには文化が肝要(Re: コメントのいらないプログラムの書き方)

そろそろ言及しておこうかな。これって「コメントのいらないプログラムの書き方」ではなくて「コメントを減らす技法 初級」だよね、それも割と暗黙の前提が多めの。

以前 id:eel3:20160425:1461594142 で言及したのだけど、ソースファイル中のコメントを減らすことは、ある水準までは技術の問題だ。しかし一定水準を超えると技術ではなく(そのプログラマが所属する)環境・文化の問題となる。

コメントの無いプログラムは、「コメントを減らす」の究極形だ。なので環境や文化の問題は避けられない。

であるにもかかわらず、件の記事は技術の問題(それも割と初級のもの)しか扱っていない上に、特定の文化圏を前提とする内容を、当該文化圏について明示せずに書いてしまっている。だからはてぶのコメント欄が割と否定的な内容になっているように思う。*1

先の記事では「『コメントのいらないプログラムの書き方』のポイント3つ!」として、次の3点を挙げているのだけど:

  1. 関数や変数に適切な名前がつけられていれば、コメントはいらない
  2. 仕様がユニットテストですべて記述されていれば、コメントはいらない
  3. コメント無しで第三者にも理解できれば、コメントはいらない

(1)は半分は技術の問題で、もう半分は特定の文化圏を前提とする内容だ。(2)と(3)は完全に特定の文化圏を前提とする内容だと言える。

ところで先ほどから何度も「文化圏」と書いているけど、この記事を書いた人の文化圏は以下の別記事から推察できる。

上記の記事を読んで、若干の想像を膨らませてから、件の記事を読めば「まあ、そういう結論になるよね」と納得できる。もっとも、例えば私の所属する文化圏は随分と異なるので、件の記事を読んだところで「でも、ウチだとそうはいかないよね」という感想しか出てこない。コメントは減らせるけど、コメントがいらなくなることはないのよ、ウチの文化圏では。

コメントを減らすための技術的要素

先にも書いたが、コメントを減らすことは、ある水準までは技術の問題だ。

DRY(Don't Repeat Yourself)の視点で考えると、コメントを書くことでソースファイル中の特定のソースコードとの間に「記述の二重化」が発生するのならば、そのコメントを削除できない検討すべきだ。

だから名前(ファイル名、クラス等のモジュールの名前、関数などのサブルーチンの名前、定数や変数の名前)には適切なものを付けるべきだし、直値ではなく名前付き定数を使うべきだし、モジュールやサブルーチンのインタフェースには極力自然なスタイルを採用すべきだ。上手くいけば、下手な名前や変なインタフェースを誤魔化すための補足コメントが不要となるので、結果としてコメントを減らすことができる。

また、ソースファイルはas is、つまり「現在の姿」を映し出すものでなくてはならない。

だから「過去の姿」である変更履歴の類は「バージョン管理システムのコミットログ」や「プロジェクト管理システムのチケットのコメント」に書くべきで、ソースファイル中のコメントに書くべきではない。古いコードをコメントアウトして残しておくなどもってのほかだ。

DRYとas isの両者の観点では、プログラムに変更が発生する可能性を考慮すると、変更が発生しやすい要素についてはコメントを書かずに済むか検討すべきだろう。なぜならば、その要素にコメントが存在する(つまり「記述の二重化」が発生している)と、プログラムの変更時にas isとなるように修正すべき部分が2倍となる可能性が生じるからだ。

だから、変更が発生しやすい「式とステートメント」に密着したコメントを極力書かずに済むように「適切な名前・適切な順序・明解なインタフェース・シンプルなアルゴリズムの採用」という点を心掛けるべきだ。式やステートメントそのものの可読性を高めれば、補足のためのコメントは少なく済む。実際のところ、世の中の「コメントを書かない」系の指摘の大半は「式とステートメント」に密着したコメントをターゲットとしている。

しかし一方で、「式とステートメント」よりは変更が発生する可能性が低い要素である「データとデータ構造」については、『プログラム書法 第2版』に曰く「データの割り付けかたについての解説をつけよう」である。

プログラムに解説をつけるためにも、もっとも効果的な方法の一つは、単にデータの割り付けかたをくわしく説明する、というものである。おもな変数について、その値としてはどんなものが可能かを示し、それが変って行くようすを説明すれば、それだけでプログラムの解説は、ずいぶん進んだといってよい。

もちろん、これを『プログラム書法』の時代と同じくコメントをして記述するのか、それとも21世紀らしく別ドキュメントに記述してリンクさせるか、という点は(そのプロジェクトの実情を考慮しつつ)議論すべきだろう。

――そう、「(そのプロジェクトの実情を考慮しつつ)議論すべき」という辺りから、技術の問題よりも環境・文化の問題の割合が増えてくる。

「コメントを書かない」を実現する上での文化的障壁

まだ私の中で決定版の答えは出ていないのだが、「コメントの少ないプログラム」から「コメントのいらないプログラム」の間には、少なくとの以下の環境・文化的障壁が存在するのではないかと考えている。

  1. 使用する言語の抽象度
  2. 開発環境
  3. そのソースファイルの性質
  4. 作成者と利用者の間の「暗黙知」の問題

まず「使用する言語の抽象度」。解くべき問題に合致している抽象度の言語を用いているなら、コメントは削りやすいものだ。例えば次のスクリプトは、中身が短く簡潔で分かりやすいので、コメントは不要かもしれない。

#!/usr/bin/awk -f
# 一列目の合計を付け足す。

{
    n += $1
    print $0
}
END {
    print n
}

しかし、これがC言語で(しかも全て自前で)実装されていたらどうだろうか? 少なくとも「このプログラムは何か? 想定している入力・出力は何か?」という情報は必要だろう。

世の中、常にモダンで抽象度の高い言語が使えるとは限らない。私なんて組み込み系の人なので、C言語縛りとか「言語仕様だけC++11(標準ライブラリはC言語と同じ)」縛りとか、そういうことが結構ある。

次に「開発環境」。「使用する言語の抽象度」で挙げた例を掘り下げて考えてみよう。

適切なドキュメントが存在し、継続的にメンテナンスされていて、かつソースファイルから関連ドキュメントへの参照(またはその逆)が容易である環境であるならば、「このプログラムは何か? 想定している入力・出力は何か?」という情報をコメントに書く必要はない。どちらかと言えば、ドキュメント化しておくべき情報だろう。

しかし、そのような開発環境が整っていないのならば、ソースファイル先頭のヘッダコメント辺りに記述しておく意味は十分にあると言える。

「そのソースファイルの性質」は、例えば「自社開発アプリケーションのコンポーネントの一部で、概ね固定されたメンバーで管理しているソースファイル」なのか、「オープンソースで公開しているライブラリで、開発チームがメンテしていて、外部の複数のプロジェクトにて組み込まれるソースファイル」なのか、というような性質の違いのことだ。

メンテナンスする人が限られていて、利用者も固定されがちで、外部への露出が少ないならば、ライブラリの公開インタフェースの情報は簡素で済む。場合によっては、インタフェース仕様のドキュメントを書かずにテストコードで示すだけでも問題ないだろう。

一方で、不特定多数の人に公開されるライブラリのソースファイルでは、問い合わせを減らすためにドキュメントを充実させる傾向にある。大抵はAPIリファレンスの類が存在するはずだ。このような環境では、ソースファイル中のコメントとしてAPI仕様を記述した上でツールでドキュメントを生成する、という手法が取られることも多い。

少なくとも私は、Unixシステムコールを叩くときも、AppleiOS SDKを使う時も、APIリファレンスとサンプルコードの双方を見る。全く知らない第三者が使うかもしれないライブラリにおいては、使い方を示すのにテストコードだけでは不十分で、どうしてもAPIリファレンスが欲しくなる。この時、横着してソースファイルにAPI仕様を記述してしまうことは結構あるものだ(もちろんそこからドキュメントを生成させる訳で、別に「コメントを読め!」という主張ではないのだが)。

「作成者と利用者の間の『暗黙知』の問題」は、ソースファイルの性質とも絡んでくる話だ。

開発メンバーがある程度固定された環境では、明示的・暗黙的にかかわらず、例えば「○○の場合は××のスタイルで書け!」のようなお作法があったりする。この環境に適応すると、ソースコード中の「××のスタイル」を目にした時に「ああ、ここは○○なのだな」と容易に逆引きできるようになる。

名前の付け方やインタフェース定義の流儀など、明快かつ合理的な作法(型)が存在し、皆が作法に従っているなら、コメントを読むまでもなく暗黙のうちに理解できてしまう部分が生じるものだ。

だから「自社開発アプリケーションのコンポーネントの一部で、概ね固定されたメンバーで管理しているソースファイル」の場合、作成者も利用者も同質性が高い上に、同質性が高い人同士での利用に留まるので、暗黙知にもとづく部分の補足コメントを削ってもあまり問題にはならない。むしろ冗長性が排されるので歓迎されるかもしれない。なぜなら、彼らからすれば「当たり前の常識」で、わざわざコメントに書くほどのことではないからだ。

しかし作成者と利用者を含むメンバーの同質性が低い場合は、安易に暗黙知に頼ってコメントを削ることは危険だ。メンバーが固定されがちな傾向にあるならば、開発者向けドキュメントに暗黙知をまとめた「お作法」の項を追加して守らせる、という方法(つまり新規参加者を教育して同質性を高める方法)は有効だ。しかしそうもいかない環境では、冗長になることを諦めて、毎度毎度コメントで暗黙知の部分を補足せざるを得なくなる。

私の場合、メンバーの同質性が高いとは言えない環境での開発が多い。なので、非公開ルーチンの類であっても、名前・引数・戻り値を十二分に練り上げた上で、ダメ押しとしてルーチンの仕様をコメントで記述した上で、コメントで記述した仕様に従ってユニットテストを書いている(それが可能な程度には詳細に記述している)。数年後に他の人がメンテナになった際に、非公開ルーチンのAPIリファレンス代わりにコメントを読んでもらうことを期待しているのだ。もちろん、その程度のコストをかけることが許される環境である、という前提があるのだが。

ソースレビューによる同質性の担保も、やはりメンバーの同質性が低い環境では機能しにくい。以前、異なるバックグラウンドを持つ開発者3人をかき集めて短期集中2ヶ月でモノを仕上げる(で、終わったら即解散する)プロジェクトに関わったことがあるのだが、バックグラウンドが違い過ぎて、コーディングスタイルの統一すら無理だった(そんな時間すらなかったこともあるけど)。なので、プロジェクトの成果物は3種類のスタイルで記述されている。同一ファイルに複数のスタイルが混在していない点が唯一の救いだろう(ファイル毎には結構異なる)。このような環境では、レビューで同質性を担保することなど望めない。

しかし継続的なプロジェクトでメンバーが固定されがちなら、ソースレビューで同質性を担保することが可能だ。そして同質性が担保されるなら、暗黙知の部分を削る余地が出てくるだろう。

まとめ

適切な技法を採用することでコメントの量を減らすことが可能だが、ある水準からは環境・文化の問題となる。だから、ソースファイルからコメントを全て取り除くためには、環境・文化の問題と向き合わなくてはならない。

「コメントの少ないプログラム」から「コメントのいらないプログラム」の間には、少なくとも以下の環境・文化的障壁が存在すると考えられる。

  1. 使用する言語の抽象度
  2. 開発環境
  3. そのソースファイルの性質
  4. 作成者と利用者の間の「暗黙知」の問題

そして、環境・文化の問題は、必ずしもクリアできる代物とは限らない。

「コメントが無くても読めるようなプログラム」は「コメントの無いソースファイル」を意味しない。「ソースファイルにコメントを書かずに済むように、ありとあらゆる合法的かつ妥当な手法を駆使した結果、そのコードを共有する文化圏の基準において最小限のコメントのみが、メンテナンスしやすいスタイルで記述されているソースファイル」のことだ。

「そのコードを共有する文化圏の基準において最小限のコメント」が「少ないコメント」と「コメントなし」のどちらを意味するかは、「文化圏の基準」に依存する。だから環境・文化の違いが存在することを念頭に置いてすり合わせしないと、いつまで経っても議論は平行線のままだ。

*1:それこそ記事のタイトルが「コメントを減らす技法 初級」とかだったら、まだ荒れなかっただろう。その代わり、読まずにスルーする人は多かっただろうね。