プログラマが知るべき97のこと/育ちのよいコード
高凝集と疎結合が優れた設計の指標だと教わったとき、戸惑ったのを覚えています。あるコードがどのくらい指標を満たしているのか、私達は判断できるのでしょうか。
巨大な関数や相互依存など、凝集や結合のまずさを示す「匂い」があるのはたしかです。鼻をつまみたくなるソフトウェアは誰にも覚えがあるでしょう。けれど一見清潔なコードをみたときも、それが本当にうまい抽象なのか不安に思うことはありませんか。
そんな時は少し視点を変え、コードの生い立ちに目を向けましょう。コードのレポジトリをチェックアウトし、それまでにチェックインされた変更、パッチをよく調べるのです。そのパッチはひとかたまりの「+」行からできていましたか? つまりパッチ単位の変更がファイルをまたがず、1つのファイルの同じ場所にまとまっていましたか?
条件にあうパッチが多いなら、凝縮や結合の指標には期待が持てそうです。疎結合なコードは変更があちこちにまたがらないはずですし、高凝集なコードは変更が1箇所にまとまるはずです。そう考えると、このような「まとまりの良い」パッチで育ったコードは冒頭の指標を満たすうまい設計だと考えて良いのではないでしょうか。
まとまりの良いパッチには、書き手にとっての利点もあります。レビューの負担が小さく、マージや取り消しも簡単なのです。変更のしやすさに多くを捧げてきたソフトウェア開発の歴史を振り返れば、優れた設計とまとまりの良いパッチの関係は自然なものに思えます。利便性のためだけでなく、設計の正しさを確かめる意味でも、私達はまとまりの良いパッチを書くよう心がけることができるでしょう。
さて。実際のコードがこう品行方正でないことを、私達は知っています。予期せぬ要望や小さな失敗を重ねるにつれて、健やかに育てたはずのコードにも「まとまりの悪い」パッチが顔を出しはじめます。野心あるコードが枠を破ろうとするのです。
先を急ぐ野心と慎重な設計を橋渡しするのがリファクタリングの役割です。リファクタリングを通じて設計を見直せば、先を急く野心が凝集や結合を損なうことはありません。ただし、リファクタリングはパッチにとって不都合なところがあります。名前の変更、クラスの引き上げといった構造上の変更は、一見「まとまりの悪い」パッチ、複数のファイルにまたがる小さな変更を生み出すからです。
リファクタリングを含むパッチはレビュアにとってのちょっとしたホラーですらあります。とはいえリファクタリングをしないコードに明るい未来はありません。まとまりの良いパッチとリファクタリング。2つの間で折り合いをつけたいところです。
折り合いをつける方法のひとつは、リファクタリングとそれ以外の変更を別のパッチとしてチェックインすることです。振舞いを変更しないリファクタリングの原則は、まとまりの悪さを和らげてくれます。読み手が振舞い自体の正しさを気にしなくて済むからです。
リファクタリングを独立したパッチに追い出せば、優れた設計を示す「まとまりの良い」パッチが残ります。将来に向けて考えをあらため、新たな一歩を踏み出すコード。野心を手なずけて立派なコードに育ったと、思わず目頭が熱くなります。