20年前に思いついたJava(ヤバ)いこと

 1992年の冬だったか、93年になっていたか。当時ダウンサイジングの流れが見えはじめてきたところで、社内の雑談に呼ばれた。
 ダウンサイジングに適した開発ルールを作ろうという委員会のようなものだ。もっとも問題意識はなんとなくあったものの、組織として特に熱心にというものでもなかったので、当時最若手で暇そうにしていた僕が引っ張り出されたわけだ。
 何の指針も無い打ち合わせ^H^H雑談、でも落としどころは「コンピュータウィルス対策をしましょう」くらいをもくろんでいたようだ。しかしながら意見募集くらいはやる。なんかないかと聞かれた私は答えた。「コンパイラとライブラリのバージョン管理をしましょう。」

 メインフレームであれば、1台の大型汎用機を大勢が使う。したがってコンパイラとサブルーチンは一元的に管理可能である。しかしながらパソコンやワークステーションが複数にまたがり、それぞれを開発者が使うとすると、CPUごとにコンパイラのバージョンが異なってもおかしくない。ましてやサブルーチンは。さらに当時見え始めていたオブジェクト指向というやつが絡むと関数をオーバーライドすれば、同じ名称で別々の動きをする関数、というか同じソースをコンパイルしたつもりでも、振る舞いが明らかに異なるロードモジュールが出来てしまう。
 これを管理するルールが必要であろうと述べたわけだ。
(以前書いた、スティーブ・ジョブスと話したというのは、これを質問したのだ。NeXTではどう解決しているのか、とね。なんか内部的に別名を持っているのかなあ、という感じだったね。関数名をシステム的に一義なものとして扱っているのかなあ〜OSのシリアル番号をかませれば可能〜違法コピーだと関数名が衝突するから結果としてコピーガードになっているとするとCoolですね。)

 当然周囲からは「意味が分からん」「そんなこと不要だろう」となかったこととされた。それ以来私は「コンパイラ、ソースのバージョンの相違による問題は起こり得ない」という建前を貫いている。
 そして、べらべらしゃべるほどのことではないので話さずにおいたのだ。

 ところが、黙っているのはよくないなあ、ということになった。どうやら私の知らないところではそういう問題が起こっているそうなのだ。そういえば途中で会社が合併したのだった。多少文化が変わったというのも十分に想像できる。

 というわけでこれからは一般論。
 前述のように、オブジェクト指向で作る場合は、継承という形で自分が中味まで知らずとも他人が作った関数が使えてしまう。で、悪いことに「バグが枯れている」というのが前提なのだ。また多態性という形で同じ名称の関数がクラスごとに違って使われることもある。少なくとも「バグが枯れた」と確信したクラスでないと、継承なんぞやってはいかんわけだ。

 これがC++やObjectPascalのようにそれなりにきちんと作られた言語であれば、仮想関数を明示的に指定できるので、デバッグが完了するまでは関数を継承できないようにしておいて、ということも可能であるが、Javaは全部仮想関数だから、勝手に下位型がつくれてしまう。上位型でバグを見つけても、そのまま修正できないということだ。下位型で使っているかもしれないからね。
 まあオーバーライドなら問題は少ないかもしれないが、クラスが入れ子になっていたりするとわけがわからん。ましてやJavaはクラス毎にロードモジュールが出来てしまう。実行時に探しに行く。(このいい加減な仕様が未だに信じられないのだが。)つまりリコンパイルしなくとも実行のたびにロードモジュールが異なるということが起こりうる。

 どうしても「作ったときにはパーフェクト」というクラスを常時作る必要があるのだ。
 修正開発ならまだ可能かもしれないが、新規開発で、しかも大規模なものだと無理だろう。上位型のテストが完了するまで、次の開発が足止めとなる。現実問題として「とりあえず作り終えたものとして」それ以降の開発を進めないといかないだろう。が大規模なシステムだと全体的に動かせるようになるのは、従来の開発パターンだと結合テスト/システムテストフェーズに入ってからだ。そこで基底クラスのバグが見つかったとしてもだねえ、もはや修正できないのよ。継承クラスはバグの見つかった基底クラスの関数をことごとくオーバーライドするか、あるいは基底クラスから修正クラスを派生させて・・・ええい!どうするっちゅうねん。もし出来たとしても、全てのテストをやり直す必要がある。

 継承による影響を無視してテストで発見されたバグだからと当たり前のように修正して、すると今まで動いていたプログラムが誤動作をし始めて、ありそうなことだなあ。え、想像できないって?一つの関数が例えば「月末営業日」を基準に計算していたとする。テストで「あ、これは月末暦日だ」と気がついて修正する。そこはそこでいいだろう。が、継承先は「月末営業日」基準計算でよかったってことはないか?もともとそういう仕様だし。すると「何もしてないのに」ある日動作がおかしくなる。途方にくれそうだ。
 いやあ具体的な失敗例知らないから説得力無いなあ。この例も頭で考えただけだし。Javaはコンパクトなシステムを徐々に発展させるというスパイラル方式でないととても扱いにくいと結論付けようとしたんだがねえ。大規模開発に適用するにはパーフェクトなプログラマがずらりと並んでいるか、あるいは開発ルールを組み替えて、バグを徹底的に早めに追い出すようにしないといけないということだ。V字モデルなんて絶対ダメよ。コードを書いた次のフェーズで、バグはなくなっていないと。結合テスト/システムテストを行う際には、正しく動くのは当たり前、でも「確認」のために行う程度のつもりでないと、です。

コンピュータネタ、目次
ホーム