はじめに:どれが一番わかりやすい?
先日、コードレビューをしてると、こんなコードを見かけました。
# コード例1
services_by_id = json['services'].index_by { it['id'] }
matched_services = project.service_ids.filter_map { services_by_id[it] }
どうでしょう?上のコードを見て、何をやっているか、すぐに理解できましたか?
僕は下のコードの方がずっとわかりやすいと思うんですよねえ。
# コード例2
services_by_id = json['services'].index_by { |service| service['id'] }
matched_services = project.service_ids.filter_map { |id| services_by_id[id] }
1行目のコードはsと略してもいいかもしれない。
文脈的にserviceのsだろうと想像できるので、これでも最初のコードよりずっとわかりやすいと思います。
# コード例3
services_by_id = json['services'].index_by { |s| s['id'] }
matched_services = project.service_ids.filter_map { |id| services_by_id[id] }
3つのコードは何が違うのか?
すでにお気づきの人もいると思いますが、コード例1とコード例2・3の違いはitを使っているかどうかです。
- コード例1 = ブロックパラメータとして
itを使っている - コード例2・3 = ブロックパラメータとして
itを使っていない(明示的なパラメータ名を与えている)
違いはたったこれだけです。
短いコードが常に正義、とは限らない
わかりやすいかどうかは主観の問題です。
「コード例1でもわかりやすさは変わらない」と思う人はいるでしょうし、むしろ「コード例1の方が好きだ」という人もいるでしょう。
ただ、本当にitを使うべきかどうかは、一度立ち止まって考えてみてほしいんですよね。
もしitを使う理由が、
「itの方が短く書けるから」
とか
「itを使っている方がなんとなく玄人っぽくてカッコいいから」
みたいな理由なのであれば、「本当にそうかな?」と僕は言いたいです。
発信する側と受け取る側で認識を揃えなければいけない「それ」
ブロックパラメータのitは日本語にすると「それ」です。
自然言語でも同じですが、「それ」が何を指すのかは文脈に依存します。
日常会話で「それ」という言葉を発した場合、発信した側と受け取る側で「それ」が指すものの認識を揃えないと、コミュニケーションが成り立ちません。
ブロックパラメータのitも同様です。
コードを書いた側とコードを読む側で「itは何であるか」の認識が揃わないと、誤解が生じたり、コードを読み解くコストが上がったりします。
「それ」が何を指すのかよくわからない場合、日常会話であれば「ごめん、『それ』っていうのは何を指してるの?」とその場で聞き返せますが、コードの場合はそうはいきません。
コードを介したコミュニケーションは、基本的に書き手から読み手への一方通行になります。
itさん「俺だよ俺。わかるだろ?」
僕はitを使ったコードを見かけると、コードが自分に対して「俺だよ、俺。言わなくてもわかるだろ?」と、上から目線で聞かれているような気持ちになります。
# コードを書いた人「itが何なのか、言わなくてもすぐわかるよね?」(←本当に??)
services_by_id = json['services'].index_by { it['id'] }
matched_services = project.service_ids.filter_map { services_by_id[it] }
別の言い方をすると、 書き手のコスト(変数名を考えたり、タイピングしたりするコスト)を読み手に転嫁している ように思えるのです。
実際、上のようなコードを読むときは、僕の頭の中では、
- えっと、この
itは・・・jsonの中にあるデータを処理していて、['id']を指定しているから、たぶんitはハッシュで、ただ、これが何のデータを表すハッシュかというと・・・えっ、なんだろう??よくわからん - こっちの
itは・・・ああ、手前にservice_idsがあるから、たぶんidか?
というように、「itを読み解くコスト」が必ず発生します(しかも前者は読み解けていないという)。
書き手がわずかなコストを払えば、読み手は楽になる
僕に言わせると、「自分が書いたコードは、書き手である自分が一番よくわかってるんだから、自分で説明するのが一番安上がりじゃん」と思います。
つまり、itを使わずに、コードの書き手が「このデータの中身は何なのか」を変数名で説明してあげればいい、というわけです。
# itを使わずに明示的なブロックパラメータでデータの中身を説明する(コードの書き手が)
services_by_id = json['services'].index_by { |service| service['id'] }
matched_services = project.service_ids.filter_map { |id| services_by_id[id] }
たしかにタイピング量やコード量は少し増えますが、それで読み手がコードを理解するコストが下がるなら、十分ペイできるコストだろう、と僕は考えます。
じゃあitはどういうときに使えばいいの?
とはいえ、Rubyにはitという機能が用意されています。
そこに機能がある以上、使う・使わないはプログラマの自由です。
当然ながら、一介のエンジニアに過ぎない僕が「itを使うな」などと言うことはできません。
ただ、上に述べたような理由から、個人的には「itはあまり多用しない方がよい」と考えています。
使ってもいい場面を挙げるなら、たとえば「irbやrails consoleで、タイピング量を減らしたいとき」とか、「自分しか使わない、書き捨てのスクリプトを書くとき」ぐらいじゃないかな、と思っています。
業務で書くようなコード、すなわち、自分以外の人が読み書きする可能性があるコードでは、原則としてitは使わない方がいいと考えています。
まあ、どこまでいっても個人の一意見にすぎないんですけどね。。
まとめ
というわけで、この記事では「ブロックパラメータのitは多用しない方がよい」という個人的な意見を述べてみました。
「いや、itでも可読性は変わらない!むしろ、短いことは正義だ!」と確固たる信念を持っている人は、そのまま使い続けてもいいと思います。
ただ、「itを使った方がRubyらしい気がするから」とか「コードは短ければ短いほどいい、って聞いたから」といった漠然とした理由でitを使っている人がいるとしたら、ちょっと考え直してみてください。
多少長くなったとしても、itを使わない方が読み手にとって優しいコードになるはずです!