コードに対してコメントを書くと実装に関するコメントになる

おととい、渋谷JVMというイベントがあって登壇させてもらったんですが、そのあとビール飲んでるときに、ぼくが「コード書く前にコメントだけ書くのいいよね」と言ったあとの返答としてきょんくん(kyon_mm)が言った言葉。

全体としては
「コード先に書いてそのコードに対してテストを書くと実装に対するテストになるし、コードを先に書いてそのコードに対してコメントを書くと実装に対するコメントになる」
という感じ。
ここに至るまでの話もおもしろかったんだけど、ここでは、コメントについて書いてみます。

まず、実装に対するコメントってどういうのかというと、こういうの。

id = findId(name);
if(id == -1){
  // idが-1だったとき登録
  register(name);
}

いやそれはコード見ればわかるから、ってやつですね。

これは、こうやるとより適切です。

id = findId(name);
if(id == -1){
  // nameに対するIDがみつからなかったとき登録
  register(name);
}

-1との比較は、IDがみつかったかどうかを判定しているということがコメントからわかりますね。

ただ、これは

final ID_NOT_FOUND = -1;

としておいて

id = findId(name);
if(id == ID_NOT_FOUND){
  register(name);
}

とするほうが適切で、そうするとコメントと同等の内容をあらわせるので、あまり意味が無かったコメントということになります。

これだとどうでしょう?

id = findId(name);
if(id == -1){
  // 登録に失敗していたとき再登録
  register(name);
}

こうすると、やりたいことは登録が成功しているかしていないかの判定であることがわかります。
※ 末尾にすこし追記してます。
registerも、単に登録しているのではなく、登録のやりなおしなのだということがわかります。
これはコードの意図をあらわしてると言えるのではないでしょうか。findIdはその実装手段として使っているだけです。もし登録失敗を判定するためによりよい手段があるのであれば、そっちのほうがいいと判断することもできます。
findIdの戻り値に関するコメントは実装に対するコメントということになります。このようなコメントでは、findIdより適切な手段があるかどうか考えることができません。

で、ここで問題は、どうやったら意図をあらわすコメントが書けるかということなんですけど、漠然と、コード書く前にコメント書くといいよねと思ってたのが、なんでそうやるといいのかが、きょんくんの言葉によって明確になった感じ。
コードを書くとき、なんらか意図があってコードを書くわけなんで、その時点でコメント書いておけば意図をあらわすコメントになるだろう、と。実装をしてしまったら、実装に気をとらわれてしまう。
きょんくんも、テストコードの中では先にコメント書く、と言ってました。たしかに、テストコードの場合はデータ準備がかさばるので、やろうと思うことを先に書いておくメリットも大きい気がします。

ということで、いいコメントが書けないという人は、コードを書く前にコメント書いておきましょう。

※追記 16:56
atsushifxさんの指摘からの話を追記しておきます。
登録に失敗したときをあらわすメソッドを

boolean couldRegister(name){
  return findId(name) != -1;
}

のようにすればいいのではないかという話もあります。確かに、そうすればコメントと同等の表現ができるようになります。
ただ、findIdが-1を返すことをもって登録ができなかったとみなすのがこの処理のコンテキストに依存するのであればメソッドをいちいち作るのは重すぎるのと、同様にコメントが入りうるところをすべてメソッドにするのも可読性を損なうかもというのもあります。
ここでは、そういった議論をするにはこのコード片では短すぎるのとで、本筋からはずれるので今回は省いていました。

※追記 4/21 16:24
コメントを書くことの是非やどのようなコメントを書けばいいかとかは、CODE COMPLETE下巻の32章にまとめられてありました。目を通すといいかも。自分でもちゃんと読んでみます。