チェスタトンのフェンスという考え方がある。
Chesterton’s Fence: A Lesson in Thinking
「なぜフェンスが建てられたのかわかるまで、決してフェンスを撤去してはならない」 という考え方だ。
フェンスを立てた理由
ソフトウェアエンジニアリングにおいて、フェンスはコードを指すと思う。
フェンスを建築するのが比較的容易なソフトウェアエンジニアリングにおいては、フェンスを取り外したくなることも多い。
コードを変更したり、削除したりするときに必要なのは、そのフェンスがいかに取り外しやすく建築されているかだけではない。なぜこのコードを書いたのか という理由が必要だ。
例えばRailsアプリ内にこういうコードがあるとする。
users.each do |user|
user.try(:cool_something)
end
このコードは、users
内の各ユーザーに対してcool_something
メソッドを呼び出そうとしている。 user.try(:cool_something)
は、user
がnil
であったり、cool_something
メソッドが存在しない場合にエラーを発生させないためのものだ。
ここで論じたいのはObject#try
の使用の是非ではない。
コードを見たときに、try
がなぜ使われているかの理由がわからないと、try
を取り除くのは難しいということだ。
一見すると、これはusers
内にnil
がありえるコードに見える。もしくはusers
内にcool_something
メソッドがないオブジェクトが混ざる可能性があるようにも見える。 このままでは、このコードをどう修正するべきかの判断が難しい。
ここに例えば以下のようなコメントがあればどうだろう。
users.each do |user|
# AdminUserとRegularUserが混在しており、cool_somethingメソッドがない場合があるのでtryを使う
user.try(:cool_something)
end
これならば、usersにありえるオブジェクトにcool_something
メソッドを生やしたり、処理を共通のコードにするのをやめたり、色々な選択肢が考えられる。
理由が書いてあることで、このコードを修正するのが容易になった。フェンスを立てた理由を先人が残すのはこのような効果がある。
コミットメッセージにはwhyを書く
フェンスを立てた理由、つまりWhyについて、よく引用されるのが以下のツイートだ。
https://x.com/t_wada/status/904916106153828352
コードには How
テストコードには What
コミットログには Why
コードコメントには Why not
を書こうという話をした
僕も概ね賛成で、これらの行動はチームメイトや未来の自分に対してのギフトになると思う。
ファイルをblameしてコミットログをみて、どうしてこのファイルができたのか、どのような事情で変更されてきたのかわかれば、そのファイルを変更したり削除したりすることは容易になるだろう。
「あるユーザーを特別扱いしたいから」、「こういうインシデントのための修正をしたいから」といった理由は、後にコードを変更する人間(あるいはLLM)の判断材料になる。まさにギフトだ。
フェンスを立てた理由をどこに残すか
コミットメッセージにWhyを書くのは結構難しいと思う。レビューに対応したコミットを積んで、結果わかりにくいコミットを積んでしまうこともある。
僕のおすすめはGitのホスティングサービスの機能を使うことだ。大体マージリクエストやプルリクエストには差分に対してコメントを残せる機能がある。そこでなぜこのコードを書いたのか、なぜこのコードを変更したのかを書くとよい。
これはレビューのためにも役立つし、後からコードを見たときに「なぜこのコードがあるのか」を知るためにも役立つ。
LLMもGitホスティングサービスまでスクレイピングしてコンテキストを理解してくれると嬉しい。(もしかしたらすでにやっているのかもしれないが)
偉そうに書いているあなたはフェンスを立てた理由をちゃんと残せていますか?
僕は自分を棚に上げる検定一級だ。