PR
1960 年生まれ,独身フリー・プログラマの生態とは? 日経ソフトウエアの人気連載「フリー・プログラマの華麗な生活」からより抜きの記事をお送りします。2001年上旬の連載開始当初から,現在に至るまでの生活を振り返って,週1回のペースで公開していく予定です。プログラミングに興味がある人もない人も,フリー・プログラマを目指している人もそうでない人も,“華麗”とはほど遠い,フリー・プログラマの生活をちょっと覗いてみませんか。
※ 記事は執筆時の情報に基づいており,現在では異なる場合があります。

 前回の記事で「オブジェクト指向だからこそ悩む」という書き方をしたが,よく考えてみるとこれはあまり正しい表現ではない。なぜなら,オブジェクト指向プログラミング(以降,OOPと略す)の仕様を持ったプログラミング言語であるからといって,大抵の場合は必ずしもOOPを多用する必要があるわけではないからだ。

 現に,少なくともいままで私が見てきた普通のプログラムに限って言えば,せいぜい関数のライブラリをモジュールにまとめるためにクラスの仕組みを流用している程度である。Javaでサーバー・アプリケーションを開発する場合や,Visual C++でWindowsアプリケーションを開発する場合は,フレームワークが用意されているので,クラスやメソッドなどの概念に親しまざるを得ない。しかし,他人が作成したクラスライブラリ(あるいはフレームワーク)を利用するレベルにとどまり,一般には自前でアプリケーション独自のクラスを定義してコーディングするところまではなかなかたどり着けないようだ。

 オブジェクト指向の概念が出てから相当に時間がたっているのに,なぜこうした状況がまかり通っているのだろうか。その理由の一つとして,設計の難しさがあるのではないかと思う。私はものごとが難しいというのには2種類あると考えている。知識として知っていないから難しいものと,感覚として持っていないから難しいものである。オブジェクト指向は後者に属する。

 例えば初期のころにこういう議論があった。チェスのゲームをオブジェクト指向でプログラミングするとして,駒がいる場所を覚えているべきなのは駒とボードのどちらだろうか。駒が次にどの位置に移動できるか判断するのはどちらだろうか,という内容である。これに対して,私が友人と頭をひねって出した一つの回答は「『審判』というクラスを用意する」というものであった。ほかに,図形集合を表示するときに,図形の描画方法を知っているべきなのは図形オブジェクトなのか,表示装置オブジェクトなのか。描画の色や線の太さなどを表示に反映する手段を知っているのはどちらなのか,という議論もあった(この回答は,WindowsやMacintoshのGDIの仕様を見ていただくとおわかりになるだろう)。

 こうした感覚や判断力を身に付けるには,それなりの環境と実践が必要不可欠になる。演習問題のプログラムを解いて「はい,回答はこれですよ,おしまい」では済まないのだ。それがよい証拠に,本誌でもときどき紹介されているUML。私は多少の興味と基本的な知識はあるものの,一向に活用できないままでいる。一つの理由は,自分の判断が正しいかどうかを議論する相手がいないからである。UMLだのオブジェクト指向だの言っている人たちは,「それはモデル化の問題だね」というかもしれない。しかし,私が感じている問題は少し違うところにある。以下,二つ例をあげてみる。

 例えば画面に表示するウィンドウに対応するWindowクラスと,そのサブクラスとしてDialogがあるとする。Dialogの下にはさらに特定用途向けのFileDialog(ファイルを選択するダイアログ)とFontDialog(フォントを選択するダイアログ)があるとしよう。ここで,ウィンドウのタイトルバーをシフト+右クリックすると,あなたが作った特別なポップアップメニューが出る機能を追加するには,どうすればよいだろうか。WindowクラスのサブクラスMyWindowを作って希望する機能を追加すれば,とりあえず解決したかに見える。しかし,この機能はDialogやその下のクラスに継承されない。Dialog以下にも同じ機能を付けたければ,MyDialogやMyFontDialogといったサブクラスをそれぞれ作らなくてはいけない。

 この問題については,ATL(Active Template Library)が明快なアプローチを示している。一つの対象をクラス化するのではなく,機能単位でクラス化しておき,実際に使うときにはじめて機能を組み合わせて利用するのだ。ただし,この手法をスマートにインプリメントするには多重継承の機能がないとかなりつらい。

 ちょっと違う例を出してみよう。例えば,CString(文字列)にPCRE(Perlライクな正規表現によるパターン・マッチング)の機能を付けたNewCStringというクラスを作ったとしても,これをアプリケーションのあらゆるところで使う気にはとてもなれないだろう。もっとも,この場合は比較的楽な代替案がある。(1)Visual C++のBSTRでやっているようにCStringと互換性を持たせることで,本当に必要なときだけNewCStringを使う,(2)Javaで見られるような,ストリームをスキャンするクラスを別に用意する,である。

 以上のような簡単な例であればコーディングを始める前にある程度見通しがつくが,中にはあるところまで行って「しまった」ということも時々ある。最悪の場合,メソッド呼び出しの順番を修正しなくてはならない羽目に陥ることもある。最初からOOPなど使わずに「単純な制御構造とサブルーチン」だけでコーディングしていればこんなリスクはないわけだ。かく言う私は,プログラムの保守・改修が死ぬほど嫌いなので,あえてOOPの道を行く。最初の開発のときにさんざん苦労しても,後で「ちょっとこれ直して」と言われたときに,さっさとこなして得意な気分にひたりたい。誤解を恐れずに言うと,私はもとより頭脳明晰なほうではないので,ある程度以上に複雑なシステムはOOPなしでは組めなくなってしまったのである。

 とはいえ,OOPにフラストレーションが生じる場合があるのも事実である。先ほどの多重継承もそうであるし,(ここでは詳しくは述べないが)「クラスの差し替え」を楽に行える仕組みがないという点も不満に感じる。後者については,こうした仕組みをコンポーネント化したものがプラットフォームによらずに使えるようになったら,ベンダー間の競争も増えて,もっとおもしろくなるのではないかと期待しているのだが。