Java言語には、クラス、メンバ、そしてローカル変数のスコープを制御するための素晴らしい仕組みがある。
僕がまだ研修中のプログラマだった頃*1は「全部publicにしておけば困る事は無い。だって、後でアクセスしたくなるかもしれないし?」と思っていた。誰にもその間違いを暴露されないまま3ヶ月の研修を修了した僕は、人生最初の受託開発プロジェクトに参加し、テストで出た不具合の山を中程まで登った時にようやく、このちょっとしたプラクティスの重要性に気がついた(そして気がついた時には遅かったんだけど)。
たとえば、全部publicにしておくと、確かに書くのは楽だと思うし、実際そのように書いている時は楽だった*2。問題は、それで楽をできるのは書くときだけだということだ。その後に待っている不具合修正とか、仕様変更対応とかは、楽どころかかなり苦しくなる。そして、不具合修正が全く無いなんてそんな素晴らしいプログラマは控えめ言ってもほとんどいないし、仕様変更対応は、必ず必要になる*3。もっと悪いことに、書いた後のこういう作業のほうが、書く作業よりも遙かに多いという事実。
ここから他の色々なプラクティスの基礎となる指針が導かれる。すなわち、
書くときのことよりも、書いた後のことを考えて書いたほうが良い
ということだ。
スコープに話をもどそう。
スコープは小さい方が良い、というのが僕の主張だ。主な理由は以下の通り。
- 自分および共同作業している他人が、うっかり触って壊す機会を減らせる。
- コードの影響範囲が小さいので、バグや変更作業による予想外の副作用を減らせる。
- イマドキのIDEが備えている補完機能が表示する選択肢に、余計なものが混ざらないで済む。
どの理由もミスを減らすことに関係している。ミスを減らすことは、書いた後の作業を軽くするので、このプラクティスの効果の説明にもなる。
能書きの後に、あまり見かけないけど効果的なローカル変数のスコープ制限*4についてのありがちな例を書いておこう。
例として、Modelクラステストのフィクスチャなどで以下のようなコードを書く場合を考える。
final FooModel foo1 = new FooModel();
final BarModel bar11 = new BarModel();
final BarModel bar12 = new BarModel();
foo1.setBars(bar11, bar12);
final FooModel foo2 = new FooModel();
final BarModel bar21 = new BarModel();
final BarModel bar22 = new BarModel();
foo1.setBars(bar11, bar22);
このコードには1箇所、間違いがあるが、すぐに気付くだろうか?
賢いIDEの警告機能を全開にしていれば、警告くらいはしてくれると思うけど、まぁ普通は、すぐには気がつかない。レッドバーが「何かが間違っている」ことを教えてくれるけれど、それがテストフィクスチャのタイプミスだなんて事までは教えてくれない。そこでテスタは無実のテスト対象のコードの方にあらぬ疑いをかけたりすることになるわけだ。
そこで、ブロックを使って変数のスコープを限定してみる。
final FooModel foo1 = new FooModel();
{
final BarModel bar11 = new BarModel();
final BarModel bar12 = new BarModel();
foo1.setBars(bar11, bar12);
}
final FooModel foo2 = new FooModel();
{
final BarModel bar21 = new BarModel();
final BarModel bar22 = new BarModel();
foo1.setBars(bar11, bar22); //ここでコンパイルエラー bar11 cannot be resolved.
}
コメントの通り、エラーが出て、何が悪いのかすぐに分かって、テスト対象コードは無罪放免、テスタのあなたは残業なし、でめでたしめでたし、というわけだ。