rpg@lucid.com
日本語訳:
daiti-m@is.aist-nara.ac.jp によるものを、牧野が改竄
私や Common Lisp と CLOS のデザイナーはみんな、MIT/Stanford 方式の設計に染まりきっている。 この方式の核心は、「正しい」やり方をせよ、という ことにつきる。そういうデザイナーにとっては、以下の点をすべて正しく満たすことが 重要である。
"悪い方がよい"原則はこれと少しだけ異なる:
しかし、私は「悪い方がよい」原則のほうが、この悪い形の表現でさえ、 「正しい」ことより生き残れるものであり、ソフトウェア開発については New Jersey アプローチの方が MIT アプローチよりもよいアプローチだと信じている。
まず、MIT/New Jerseyアプローチの区別が妥当なものであり、それぞれの側が 自分の方が優れていると信じていることを示すエピソードから始めよう。
あるとき、MIT 出身と Berkeley
出身(ただし、Unix開発に携わっていた)の二人の有名人が
OSの問題を話し合うために集まった。
MITの彼は ITS (MIT 人工知能研究所のOS) に精通しており、
Unix のソースコードを読んでいた。彼は Unix がどのように「PC loser-ing」問題を
解決しているかに興味を持った。「PC loser-ing」問題は
ユーザプログラムがI/Oバッファのような大規模な状態を内部に持つ、時間のかかる操作を
システムに要求したときに起こる。もし操作の実行中に割り込みがかかったら、
ユーザプログラムの状態は保存されなければならない。しかしシステムルーチン起動は通常1つの命令であるため、ユーザプログラムの
現在の命令の実行位置を示すプログラムカウンタ (PC) はプロセスの状態を適切に保持していない。そこでシステムはその命令が実行される
前に戻るか、そのまま命令を実行したことにして先に進むかしなければならない。
「正しい」やり方はもちろん、前に戻ってプログラムカウンタを
システムルーチンを起動した命令に戻し、ユーザプログラムに復帰するとそれがシステムルーチンを再実行するようににすることである。
プログラムカウンタがユーザモード (MITではユーザ(user)のことを愛情をこめて敗者
(loser)と呼ぶ) に強制的に戻されることから、このことを
「PC loser-ing」と呼ぶ。
MITの男はソースの中にこの問題に対処するコードを見つけられ
なかったので、New Jersey の男にどうやってこの問題に対処しているのか
尋ねた。New Jersey の男は、Unix の連中はこの問題に気付いているが、
解決はシステムルーチンは常に終了し、ただし
システムルーチンが正常に動作を完了しなかったらエラーを返すように
することだと答えた。したがって、正しいユーザのプログラムは
エラーがあるかをチェックしてそのシステムルーチンを再実行するかどうか決
めないといけないのだ。
MITの男はこの解決は気に入らなかったが、それはもちろんこの解決が
「正しい」やり方ではないからだった。
New Jerseyの男は、このUnixの解決は正しい、なぜならUnixの設計哲学は
単純さにあるのであって、「正しい」ことは複雑過ぎるからだと言った。
それだけでなく、プログラマがここにこの余分なテストとループのコードを
入れることは簡単なことだ。
MITの男はそれに対して、実装は単純だがインターフェースが複雑すぎることを指摘した。
New Jerseyの男は、Unixでは適切なトレードオフが
行われていると答えた。すなわち、実装の単純さの方がインターフェースの単純さより
重要なのだと。
MITの男はそれを聞いて「やわらかい鶏料理を作るには屈強な男が必要なことも ある」とかなんとかつぶやいたが、New Jerseyの男には理解できない ようだった[筆者にもよくわからない]。
ここで私は、「悪い方がよい」原則の方がよりよい原則であると主張したい。 CはUnixを書くためにデザインされたものであり、New Jerseyアプローチに従って デザインされている。従ってCは良いコンパイラが書きやすい言語だが、 同時にそれはプログラマがコンパイラに読みやすいようにコードを書くことを 要求する。Cのことを高機能なアセンブラだと呼んだ人もいるほどである。 初期のUnixとCコンパイラはどちらも単純な構造を持っており、移植は簡単で、 ハード資源の少ないマシンでも動作し、OSとプログラミング言語に対して人が望むものの50%―80%程度を提供することができた。
ある時点で存在するコンピュータの半分はコンピュータの中央値より 遅いかメモリが少ないが、UnixとCはそういう機械でも問題なく動く。 「悪い方がよい」という原則は実装の単純さに何よりの重きを置くもので あるから、それはUnixとCがそういう機械にも容易に移植できることを保証する わけである。従って、望まれることの50%の機能を持つ Unix と C で 充分なのであれば、それらは至るところに広まることになる。 そして実際そうなってきた。
Unix と C は究極のコンピュータウイルスである。
「悪い方がよい」アプローチのさらなる利点は、プログラマが安全性や便利さ を多少犠牲にしてでも、速く、システム資源をあまり消費しないプログラムを 書くように条件付けられることである。New Jersey アプローチを使って書かれたプログラムは 小さいコンピュータでも大きなコンピュータでも同様に動き、プログラムは 容易に移植が可能なものとなる─なぜならそれはウイルスの上に書かれて いるのだから!。
ただし、最初の「ウイルス」が十分によいものでなければならないことは
覚えておかなければならない。もしそうであれば、移植できるかぎり
そのウイルスが広まっていくことは保証される。
一度ウイルスが広まってしまえば、それをよりよいものにする圧力が
生まれ、完全なものの 90%に近い機能が実現するかもしれない。
しかしユーザは完全ではないものを受け入れるようにすでに条件付けられて
いる。従って,「悪い方がよい」原則によるソフトウェアは最初に
多くの人に受け入れられ、次にユーザをあまり多くを望まないように条件付け、
最後にほとんど「正しい」所まで改善が続けられる
ことになるのである。
具体例を挙げるなら、1987年の時点ではまだLispコンパイラはCコンパイラと
同等の性能を持っていたが,その後では C コンパイラを改善しようとする人々の方が
Lispコンパイラを改善しようとする人々よりずっと多かったのだ。
良いことは1995年には我々がよいOSとよいプログラミング言語を持つ ことであり、不幸はそれが Unix と C++ となるだろうことである。
最後に、「悪い方がよい」原則にはまだよい点がある。New Jersey アプローチによる 言語とシステムは単一の複雑なソフトウェアを構築するには力不足であるため、 大きなシステムは構成要素を再利用する設計にならざるを 得ないのである。そこで、要素を統合してシステムを作る伝統が作られることになる。
では、「正しい」アプローチではどうなるだろう? 基本的なシナリオは2つある:『複雑巨大システム』に至るシナリオと 『ダイヤモンドのような貴石』となるシナリオとである。
『複雑巨大システム』となるシナリオはこうなる:
まず最初に、正しいものがデザインされなければならない。それから、 その実装もデザインされなければならない。ついに、それは実装される。 それは正しいものだから、もちろん望まれる機能のほとんど100%を果たす。 実装の単純さは決して考慮に入れられることはない、そのために 実装には長い時間が必要になる。それは大きく、複雑なものになる。 それを適切に使うには,複雑な道具が必要になる。実装の最後の20%に努力の 80%が費やされ、リリースするには長い時間が必要となる。そしてそれは もっとも進んだハードの上でないと満足に動作しない。
『ダイヤモンドの輝きを放つ貴石』となるシナリオはこうなる:
「正しい」ものをデザインするには無限の時間がかかるが、その途中では それはいつもきわめて小さなものになる。 それを速く走るように実装するのは不可能か、ほとんどの実装者の能力を超えている。
この2つのシナリオはそれぞれ Common Lisp と Scheme のたどった道である。
また、最初のシナリオは古典的な人工知能プログラムのたどった道でもある。
「正しい」ものはしばしば単一のソフトウェアであるが、これは 「正しい」ものが単一のものとして設計されることが多いからにすぎない。 つまり、これは偶然にすぎない。
このことから学ぶべき教訓は、最初に「正しい」ものをめざすことはしばしば 望ましくないということである。とりあえず「正しい」ことの半分はできるものを 作り、ウイルスのように広める方がよい。いったん人々がそれを使うようになれば、 9割方「正しく」なるまで改善が行われるだろう。
間違った教訓はこの寓話を文字通りにとって、人工知能プログラムにとって C が正しい言語だと結論することである。50%の解は基本的には十分なものでなければ ならなかったが、この場合はそうではない。
しかし、Lisp コミュニティは Lisp の設計に対する姿勢を 考え直さねばならないということはいえよう。このことについてはもう少し後で 述べようと思う。
2003/02/12