プログラミング文章読本~唯物論は正しいか?
2008.05.23
オブジェクト指向言語が紹介され始めた頃(80年代初期)に、「Object Oriented て具体的にどういうこと?」というコトバの問題で、ある学者が「唯物型(プログラミング)」という訳はどうか...などと提案していた覚えがあります。手続型言語のアドオンとして実装された言語でないならば、オブジェクト指向言語は、
すべてモノ(オブジェクト)だ!
ということになるわけで、「唯物型」というのもそれなりに根拠がないわけではないですね!→昔話
しかし、その後、オブジェクト指向プログラミングが成熟を重ねていくにつれ、「オブジェクト指向のプログラミング・ノウハウ」が蓄積されてきて、それが「デザインパターン」(狭く GoF でまとめたモノを指すと今回はしておきます)として結実したわけです。このデザインパターンの「思想」を非常におおまかに(哲学として)捉えなおすと、それは、
モノはモノなんだけども、モノとモノとの間の関係に着目して、「役割を担ったモノ」として捉えよう!
というのが、一番の重要なポイントなのでは...と思うのです。ここまでOK?
さて、よくコーディング規約では、
変数名は、それが「何であるか」をちゃんと記述するような名前をつけましょう!
と言われるのがフツーです。まあ、これが「正しくない!」と言うわけではありません。とはいえ、この「何であるか」ということにこだわりすぎると、こういうコードになります。
for( int indexOfSomeList = 0; indexOfSomeList <= sizeOfSomeList; indexOfSomeList++ ) {
SomeObject someObjectInTheListAtPresent = someList.get(indexOfSomeList);
someObjectInTheListAtPresent.executeSomeFunction( argumentForSomeFunction );
}
あ、勿論パロディですってば! 念のためシンプルな書き方と比較しましょうか?
for( int i = 0; i < someList.size(); i++ ) {
SomeObject at = someList.get(i);
at.execute( argument );
}
さて、どちらが判りやすいでしょうか.....少なくとも私は、「それが何なのか」を丁寧に記述したコードは、きわめて冗長に感じます。情報が多くなりすぎて、構造を覆い隠してしまっているという印象ですね。その情報は繰り返しに過ぎません。逆に for 文の中のループカウンタが「ホントに同じカウンタを示しているか?」ということさえも、一見して読み取りにくいわけです。
またこのルーチンを別なところで呼ぶことになりました。そしたら、実際にこのメソッドに渡されるのは、SomeObject の派生クラスのリストが渡されることになり、その派生クラスでは、executeSomeFunction() の「派生オブジェクトに対して、someFunctionをせよ!」というのが、直感的に意味が通らない表現になってしまいました....
たとえ話: 「鳥」というクラスに「飛べ」というメソッドは意味があるけども、「ダチョウ」という「鳥」派生クラスだと「飛べ」というメソッドは何をするんでしょう? だったら、「飛べ」というメソッドは過剰に意味を限定しすぎているのであり、「移動せよ」の方が適切では?
....要するにこれ、過剰に詳細に「何であるか」を説明的に記述してしまったために、機能的な柔軟性を失ってしまうケースがある、ということです。残念ながら、プログラムの構造よりも、「変数が何を示すか?」の方のがずっと変化しやすいのです。
勿論私は、インスタンス変数の命名に、「それが何を示すか記述的な名前をつける」ことに反対するわけではなく、それを薦めます。
しかし、引数名や自動変数には、「それが何であるか」を示す名前を付けるよりも、「それがどう振る舞うか?」に注目して名前を付けるべきだ、と思います。i, j, k という変数ならば、プログラマはフツーにそれらを「ループカウンタ」だと理解しますし、len や size と付いていれば、注目しているコレクションや文字列のサイズであろう、と了解します。あるいは、sum ならばループの中で蓄積される値であることを期待しますし、ret という名前ならば、それが戻り値を強く関連付けられている変数だと理解します....こういう名前は「そのメソッドの中でどう振る舞うか」の役割を示す変数名なのです。このような「振る舞いの名前」を見れば、その動きについて、予測が付きます: 予測がつく分、プログラムを意味の通った構造としてすんなりと把握できるというメリットは大きいのです。
逆なメリットもあります。
インスタンス変数は 「それが何か示す説明的な(長い)名前」
自動変数は 「役割を示すかなり固定した(短い)名前」
だったら一見して簡単に区別が付きます。しかしそれよりも重要なのは、こういう風に「何に対してするのか」よりも、「どう動くものなのか」をメソッドが明示するようになると、「メソッドAとメソッドBは実は同じ構造を持っているから、これらは一緒にまとめてやった方がいい」というリファクタリング発想を強く促す、という点です。
2つのリストをインスタンス変数で持っているクラスだとしましょう。最初は個別にそのリストについて探索をするメソッドを書いていました。
MyObject findListA( int a ) {
for( int i = 0; i < this.listA.size(); i++ ) {
MyObject object = this.listA.get(i);
if( object.getA() == a ) {
return object;
}
}
return null;
}
しかし、「これら構造はまったく一緒じゃん!」と気がついたとき、それは
MyObject find( List<MyObjext> list, int a ) {
というインターフェイスに変わり、コーラー側で「何からfind するか」を、インスタンス変数を引数渡しすることで、選択することになります。シンプルに書いていればいるほど、構造が全面に出て、「構造の共通性」に気づきやすくなります。これは「何であるか」ではなくて、「どう振る舞うか」を重視したことによるメリットなのです。
「何なのか」を記述する「唯物論」ではなくて、「どう振る舞うか」を大きなパターンとして捉える視点を今回強調したわけですが、ホントは情報の量と人間にとっての理解しやすさ、というのは反比例したりするわけです(情報理論を勉強するといいですが)。「情報が多いこと」が必ずしも理解を助けるのではなく、「情報を最低限に絞ること」が本当はデザインの極意なのではないのでしょうか。
投稿者 : 杉浦 こずえ | 投稿日時 : 2008.05.23 13:35





