Marimpod chomswiki (93)docs (15)gallery (13)一行物語集 (8)

Design Principles Behind Smalltalk (in Japanese)

Last edited: 8:18:25 am on 9 October 2003

!->Original  ->changelog ->調べた言葉


Smalltalkの底を流れる設計思想

Daniel H. H. Ingalls


Smalltalkプロジェクトは私たち一人一人が持つ創造性を計算機によって支援することを目指している。このプロジェクトの源は創造的な個性と最高性能のハードウェアがともに創造する未来にある。はじめに私たちは二つのことばの研究に注力することに決めた。描写するためのことば(プログラミング言語)と対話するためのことば(ユーザーインターフェイス)だ。これはそれぞれ人間の精神と計算機とがもつ現実世界のモデルを結ぶもの、人間と計算機のコミュニケーションの仕方を融和させるものになる。Smalltalkプロジェクトは2年から4年のサイクルを追って発展してきた。このサイクルと科学的な探求の手法[*]との間には対応関係を見出すことができる:

  • 今あるシステムでアプリケーションをつくる(観察する)
  • その経験にしたがって、言語を設計しなおす(理論を構築する)
  • 新しい設計にしたがって、新たなシステムをつくる(検証できるような仮説をたてる)

Smalltalk-80システムはこのサイクルの5周目にあたる。この記事ではこのプロジェクトをすすめる中で認識するにいたった一般的な原則をいくつか紹介しようと思う。本文中でSmalltalkプロジェクトにふれることは多くなるが、ここに紹介する原則は普遍的なものであり、他のシステムの評価や将来の開発に役立つものと考えている。


技術的なところに立ち入るまえに、まずSmalltalkプロジェクトの精神をあらわすともいえる原則から始めよう。

達人有可:システムが創造性を支援するには、それは一人の人間が完全に理解できるものでなければならない

ここでのポイントはヒトの秘めている可能性は個々人のなかに現われるということだ。この可能性を現実のものとするためには、一人の人間がマスターできるような道具が必要である。システムを使う者とシステムとの間に立ちはだかる壁はいずれ創造性をもさまたげる壁になる。また、システムの中で変更不可能な部分や、普遍性に欠ける部分もきっとバリアの原因になるだろう。さらにシステムの中のある部分だけが違った仕組みでうごいていれば、その部分をコントロールするのに余分な労力が必要になる。そしてそうした余分な負荷によって最終的な結果がそこなわれるかもしれないし、その分野をさらに追究する試みをきっとさまたげるだろう。以上の事柄から考察して、設計における一般的な原則をみちびき出すことができる;

よい設計とは:システムは最小限の変更不可能な部分から作られなければならず、これはなるだけ普遍的でなければならない。システム全体が一つの枠組みにおさまっていなければならない。


^

言語


計算機の言語を設計するためのヒントを探しまわる必要などない。それはすぐ手の届くところにある。ヒトがどんなふうにして考え,コミュニケーションしているかについてわかっていることはすべてあてはまるのだ。ヒトの思考とコミュニケーションのしくみは何百万年と開発されてきたのだから、すじの通ったものとして一目おくべきだと思われる。さらに言えば、この設計のもとで来る百万年間やらないといけないのだから、我々の思考を計算機にあわせるよりも、その逆をやった方が時間の節約にもなるだろう。

図1はこの議論の中のおもな要素を図示したものだ。人間は精神と身体をもったものとして表現されている。身体は第一次の経験の場であり、この文章の論旨では世界を知覚し、意思を実行にうつすための物理的な手段だ。身体における経験は精神によって記録され、処理される。創造的な思考とは(具体的なしくみはおくとして)、情報が自由にわきあがるように精神にたちあらわれることと考えられる。その情報への手がかりとなるのが言語だ。

言語の目的:コミュニケーションの枠組みをあたえること

二人のヒトのあいだの相互作用は図1では二つの曲線であらわされている。実線でかかれた曲線は陽のコミュニケーションをあらわす;実際に発せられ、知覚される言葉や動きだ。点線でかかれた曲線は陰のコミュニケーションをあらわす;二人のヒトが共有し、陽のコミュニケーションのコンテキストをなしている文化や経験だ。ヒトのあいだの対話では、実際のコミュニケーションのかなりの部分が二人の共有する文脈への参照をとおして実現されており、人間の言語はそうした参照をよりどころにつくられている。このことは計算機の言語にもあてはまる。

図1の二人のうち一人と計算機とをおきかえて考えることもできる。この場合、「身体」は情報を表示する装置と人間からの入力をうけつける装置とになる。そして計算機の「精神」は内部メモリ、処理ユニットとその中身をあわせたものになる。計算機の言語の設計にはさまざまな要素が含まれていることが図1からわかる。

言語設計の広がり:計算機を使うための言語の設計は、内部のモデル、外部の媒体、そして人間と計算機におけるこれらの相互作用への考察を含んだものでなければならない

このせいもあって、計算機の言語を狭い意味でとらえる人にSmalltalkの特徴を説明するのは難しい。Smalltalkは単に処理の手続きをもっとよくとりまとめるための方法とかメモリ管理の新手法というだけではない。また単なる拡張可能なデータ型のピラミッドとかGUIだとかというわけでもない。Smalltalkはこれらすべてプラス、図1に示された対話をサポートするのに必要なことすべてなのだ。


図1


[図1]言語設計のスコープ。二人のヒト(か、一人のヒトと計算機)の間のコミュニケーションには二つのレベルがある。陽のコミュニケーションはあるメッセージによって伝達される情報を含む。陰のコミュニケーションは対話しているものが共有する前提を含む。


^

対話するオブジェクト


精神は今現在および過去の膨大な経験を通りぬけている。このあるがままの経験から自己と世界との調和をかんじることも可能だ。だが、この世界で何か役割をはたしたいなら−−文字通り役を演じたいなら、境界線を引かねばならない[*]。境界線を引くことで世界の中のある一つの'もの'が見分けられるようになり、同時にのこりのもの全てが「その'もの'ではないもの」になる。境界線のひき方として、その'もの'自体を目印にするのはまずは第一歩となる。だがこれでは自由自在に役を演じるわけにはいかない。「あそこにあるあの椅子」のことで何か言おうとするとき、毎回毎回「あの椅子」を特定し、境界線をひく作業を繰りかえさねばならないのだ。ここが「参照」の役立つ点だ。話題にしたい対象と、ある単義的(ユニークな)目印とを関連づけたら、その後はその目印を示すだけでもとのオブジェクトのことに言及できるのだ。

前に計算機のシステムは人間の精神にあるのと互換性のあるモデルをもたなければならないといった。それゆえ、

オブジェクト:計算機の言語は「オブジェクト」の概念をサポートし、その言語の世界の中でオブジェクトを参照するための統一的手段を提供しなければならない

Smalltalkのメモリ管理機構はシステム全体のメモリをオブジェクトの考え方にもとに処理している。先の原則の統一的な参照は単にシステムの中のオブジェクトに一つずつ整数をわりあてることで実現されている。この統一性は重要だ。なぜならシステムの中の変数がさまざまに違った値をとれると同時にシンプルなメモリセルで実装できることを意味するからだ。オブジェクトは式が評価されたときにつくられ、統一的な参照方法で使いまわすことができる。そうして、使いまわすときにはオブジェクトの記憶のために場所をあけておく必要がないのだ。オブジェクトへの参照がシステムに存在しなくなったら、オブジェクトも消え、その占めていた場所は回収される。こうした挙動はオブジェクトというメタファーを完全にサポートするのに必要である。

メモリ管理:本当に「オブジェクト指向」であるためには、計算機のシステムは全自動のメモリ管理を提供せねばならない

言語がうまく機能しているかをみるには、実際に実行されていることをプログラムがさせているように見えるか観察すればよい。メモリ管理に関係した命令がちらほらしているようなら、その言語の内部モデルは人間の精神にあるものとあまり対応していない。誰かに何か言うにはその人を初期化しないといけないとか、何か言い終わったということをその人に伝えないといけないとか、それを忘れてしまうかもしれないなんてことがあるだろうか?

現実世界に存在する'もの'にはそれぞれ固有の一生がある。同様に、我々の脳も頭にあるオブジェクトそれぞれを独立して処理し、記憶することができる。このことから3番目の設計原則がみちびき出せる:

メッセージ:計算処理はオブジェクトに備わっている内的な能力であるべきで、メッセージを送ることですべて同じように起動されねばならない



ちょうどオブジェクトのメモリが明示的に管理されているとプログラムがごちゃごちゃになるように、計算処理が外部的におこなわれていると、システムのコントロールも込み入ってしまう。たとえばある数に5を足す、という処理を考えてみよう。たいていの計算機システムでは、コンパイラがこの「ある数」がどういうデータ型かを割りだして、5を足す、というコードを生成する。このようなやり方ではオブジェクト指向たり得ない。というのは、「ある数」の型をコンパイラが決定することはできないからだ(このことは後でまた触れよう)。ほかに考えられるのは、加算ルーチンを呼び出して引数の型をわりだし、適切な処理をさせるやり方だ。これはいいアプローチとはいえない。初心者が自分でつくった「数」クラスをためしてみたい、というとき、このすべての運命を握るともいえる加算ルーチンをいじらなくてはいけないのだ。またデザイン上も貧弱なものだ。なぜなら、オブジェクト内部にかかわる情報がシステム中にちらばることになるからだ。

Smalltalkでは格段にきれいな解をあたえている。操作の実際の処理方法は受け手本人が一番よく知っているだろう、という了解のもと、してほしい操作の「名前」と引数(あれば)とをメッセージとして「数」に送るのだ。ビットをぎしぎし挽きながらプロセッサーがデータ構造をめちゃくちゃに破壊するかわりに、ここでは礼儀正しいオブジェクトたちが望みをかなえてくれまいかと丁重にお願いしあっているのだ。メッセージの伝達だけがオブジェクトの外側で行われる処理であり、メッセージはオブジェクト間を行き来するのだから、これは理想的な姿だ。ここで、よい設計の原則を言語設計にしぼって言いかえてみよう;

統一的なメタファー:言語はあらゆる場面に統一的に適用できるような強力なメタファーをもとに設計されるべきである



この原則に関して成功している例を挙げると;LISP、これはリンクされた構造というモデルに基づいている。APL、配列というモデルに基づく。そしてSmalltalkは対話するオブジェクトというモデルに基づいている。これらのどの言語においても、どんなに大きなアプリケーションでもシステムを形作る基礎的ユニットと同じ枠組みでとらえ、あつかうことができる。特にSmalltalkでは、最も基本的なオブジェクト間の相互作用と、一番上のレベルの、計算機とユーザーの間の相互作用とを同じようにみなすことができる。Smalltalkのすべてのオブジェクトは、なんと整数までもが、メッセージの組、プロトコルをもっており、自分自身との通信方法を定義している。内部では、オブジェクトはローカルな記憶領域をもつかもしれないし、コミュニケーションに必要な前提を暗に適用するかもしれない。例えば「+ 5」(5を足す)というメッセージでは、被加数はメッセージを受け取った「数」オブジェクトの現在の値である、という暗示的仮定を含んでいる。


^

組織化


統一的メタファーは複雑なシステムを構築できるような枠組みをあたえるのだった。この複雑さをうまく管理するための組織化上の原則をいくつか紹介しよう。まずは、

モジュラリティ:複雑なシステムの構成部品はほかの構成部品の内部仕様に依存してはいけない



図2


[図2]システムの複雑さ。システムの構成部品の数が増えるにつれ、予想外の相互作用がおきる可能性は急激におおきくなる。このため、計算機の言語はそうした依存がなるべく少なくなるように設計されねばならない。



この原則を図2に図示する。仮にシステムの構成部品がN個あったとすれば、それらの間の依存関係はざっとNの2乗はあることになる。計算機システムによって人間のやる込みいった事どもを支援しようとするなら、そうした依存関係がなるべく少なくなるように設計する必要がある。メッセージ伝達のメタファーでは、メッセージの意図(これはメッセージ名に体現されている)と、メッセージの受け手がその意図を実現するのにつかう実際の方法とを分離することでモジュラリティを達成している。オブジェクト内部の状態も同じメッセージ伝達という方式でアクセスされるから、構造上の情報もまもられることになる。

似たような構成部品を一まとめにすることでシステムを簡単にできることが多い。従来の型にはまったプログラミング言語ではデータ型をつかうことで「一まとめ」にしてきたが、Smalltalkではクラスをつかう。クラスは他のオブジェクトがどんなものかを説明するものだ−オブジェクトの内部の状態、対応できるメッセージのプロトコル、メッセージに反応するときの実際のメソッド。そうして説明されたオブジェクトはそのクラスのインスタンスとよばれる。そして、クラスそのものまでもがこの枠組みにおさまっている。クラスはClassクラスのインスタンスなのだ。Classクラスはオブジェクトがどんなものかを説明するためのプロトコルや実際のメソッドを説明したものとなっている。

分類:言語は、似たオブジェクトを分類する手段、それにシステムの基礎をなす分類群と同格の分類群をユーザーが新たに追加する手段を提供せねばならない

分類は「らしさ」らしさの実体化だ。言いかえると、たとえばあるヒトが椅子をみたとすると、その経験は文字通り「その椅子そのもの」に関するものと、抽象的に「その、椅子らしいもの」に関するものとみなされる。このような抽象概念は「似た」経験をいっしょにしてしまうというヒトの精神の不思議な能力によって生じるもので、この抽象概念は精神の中では実際の具体的なものとは別の'もの'としてあらわれる−プラトン的な椅子、あるいは椅子らしさ、として。

クラスはSmalltalkで拡張をおこなうための主たる方法だ。たとえば、音楽を扱えるようなシステムをつくろうと思えば、音[Note]、メロディー[Melody]、楽譜[Score]、音色[Timbre]、プレーヤー[Player]などのクラスを追加することになるだろう。これらのクラスは現実の'もの'の計算機内部での表現であり、メッセージ授受のためのプロトコルを記述したものだ。上の「分類」の原則にある「同格の」という語は重要で、というのもそれによってシステムが設計されたとおりに使われることが保証されるからだ。いいかえれば、メロディーはピッチ、長さその他のパラメーターをあらわす整数[Integers]のその場しのぎの集合で表現することもできるが、もし言語が音[Notes]も整数[Integers]と同じようにたやすくあつかえるなら、言語の使用者は自然メロディーを音[Notes]の集合として表現するだろう、ということだ。デザインの各段階で、人間はシステムが提供するなかで一番効果的な表現を自然と選ぶものだ。モジュラリティの原則はシステムの処理上の構成部品について興味深い原則を示唆している;

ポリモルフィズム:プログラムはオブジェクトの振るまいだけを規定すべきであって、オブジェクトの表現を規定してはならない。



陳腐な言いかたをすれば、プログラムはあるオブジェクトがSmallIntegerだとかLargeIntegerだとか言ってはならず、ただ整数のプロトコルに反応する、とだけ言わねばならないということだ。こうした包括的な記述は現実世界のモデル化には重要だ。

たとえば、自動車の交通シミュレーションを考えてみよう。そうしたシステムの中の処理にはさまざまな乗り物が登場する。試しに、新たに道路清掃車を走らせたいとしよう。もし扱っているオブジェクトにプログラムのコードが依存していたら、こうした簡単な拡張をするのにかなりの量の計算が(再コンパイルのかたちで)いるだろうし、もしかしたらエラーも出るかもしれない。メッセージ伝達のインターフェイスはこうした拡張に適した枠組みを提供している。道路清掃車もほかの乗り物と同じプロトコルをサポートしていれば、これをシミュレーションに組み入れるのに何も変える必要はないのだ。

因数分解またはファクタリング:システムの独立した各構成部品は1ヶ所にだけ存在する

これにはたくさんの理由がある。第一に、システムへの追加が1ヶ所だけでよいなら、時間と労力とスペースの節約になる。第二に、必要とする構成部品をユーザーがもっと簡単に見つけられる。第三に、ちゃんとファクタリングされていなければ、加えた変更をシンクロしたり、依存関係にある構成部品のあいだに矛盾がないことを確かにしたりするのが難しくなる。ファクタリングがうまくなされていないと、モジュラリティの原則に反することになるのがわかる。

Smalltalkではうまくファクタリングされたデザインが継承を通じて促進される。すべてのクラスはそれぞれのスーパークラスからふるまいを継承している。この継承関係はだんだん一般化していきながらクラスからクラスへと続き、最終的にはObjectクラスで終わる。Objectクラスはシステムのすべてのオブジェクトのデフォルトの振るまいを記述している。上の交通シミュレーションでは、道路清掃車クラスStreetSweeper(と、ほかの乗り物のクラスすべて)はより一般的な乗り物クラスVehicleのサブクラスとして記述され、そうして乗り物として適切な振るまいを継承し、同じ構想をあちこちで繰りかえし記述するのが避けられるのだ。継承からさらにファクタリングの実際的な恩恵がみちびきだされる;

てこの原理、または影響力:システムがよくファクタリングされていれば、ユーザーとインプリメンターの双方が大きな影響力をもつ



オブジェクトの順序づけされた集合[ordered collection]を例にとって考えてみよう。SmalltalkではユーザーはsortというメッセージをOrderedCollectionクラスに定義するだろう。これが実装されたら、順序づけされた集合のかたちをとったすべてのクラスは継承をつうじてただちにこの新しい能力を身につけるのだ。余談だが、テキストをアルファベット順にするのも、数を並べかえるのもこの同じメソッドで出来るのは特筆に価するだろう。比較のプロトコルはテキストのクラスと数のクラスそれぞれが認識するからだ。

さて、インプリメンターがうける組織化の恩恵は明白だ。まずは、実装しないといけないプリミティブが少なくなることだ。たとえば、Smalltalkではすべてのグラフィックがただ一つのプリミティブで実行されている。一つしか課題がなければ、ちょっとした改良がシステム全体にわたって増幅されることを胸に、インプリメンターはひとつひとつの命令にていねいな注意をむけることができる。当然ながら計算機システム全体をサポートするのに充分なプリミティブの組とはどんなものか、疑問がわいてくる。この疑問への答えは、ヴァーチャルマシンの仕様とよばれる;

ヴァーチャルマシン:ヴァーチャルマシンの仕様は技術の適用のための枠組みをあたえる

Smalltalkのヴァーチャルマシンはメモリ管理にはオブジェクト指向なモデルを、処理にはメッセージ指向なモデルを、情報の視覚的な表示にはビットマップモデルをあたえている。マイクロコードの使用をとおして、そして最終的にはハードウェアをとおして、ほかの長所を犠牲にすることなくシステムのパフォーマンスを大幅に向上することができる。


^

ユーザーインターフェイス


ユーザーインターフェイスは単純にいえば、コミュニケーションのほとんどが視覚的なものである言語だ。視覚的な表現は既存の人間の文化と大きくかさなるから、ここでは美学が大きな位置をしめることになる。また、計算機システムの能力は最終的にはユーザーインターフェイスをつうじて人間の手にもたらされるのだから、柔軟性もまた欠くことができない。ユーザーインターフェイスが充分柔軟性をもっているかどうかの実践的な指針は次のようなオブジェクト指向な原則であたえることができる;

反応できること:ユーザーがアクセスできる部品のすべてはユーザーが観察し操作するのに適した方法で自らを表現できなければならない

Smalltalkでは、この基準は対話するオブジェクトというモデルで充分にみたされている。定義上、各オブジェクトは対話のための適切なメッセージのプロトコルを提供している。このプロトコルの本質はそのオブジェクトに特化されたマイクロ言語だ。ユーザーインターフェイスのレベルでは、スクリーン上のオブジェクトに対する適切な言語は視覚的に(テキスト、メニューやピクチャで)表示され、キーボードへの入力とポインティング装置の使用によって感知される。

オペレーティングシステムがこの原則を破っているようであることはちょっと注目すべきだろう。プログラマーは一貫した記述の枠組みをはなれ、蓄積されたコンテキストをあとにし、まったくかけ離れた、そしてたいていはとても原始的な環境を相手にしなければならないのだ。そんな必要はない;

オペレーティングシステム:オペレーティングシステムは言語におさまりきらないものを集めたもので、これは存在すべきでない

従来オペレーティングシステムによって実行されてきたタスクの中でごく自然にSmalltalkにとりこまれているものの例をあげよう:

  • メモリ管理−全自動。オブジェクトはクラスにメッセージがおくられたときに作られ、自分自身への参照がなくなったときに回収される。仮想メモリをとおしたアドレス空間の拡張も同じように単純明快だ。
  • ファイルシステム−FilesDirectoriesといったファイルアクセスをサポートするメッセージプロトコルをもったオブジェクトの形でSmalltalkの枠組みのなかに含まれている。
  • ディスプレイのあつかい−ディスプレイはFormクラスのインスタンスで、ずっと目にみえている。Formクラスに定義された画像操作のためのメッセージは目にみえるイメージを変更するのに使われる。
  • キーボード入力−ユーザーからの入力をうける装置はオブジェクトとしてモデル化されていて、状態をたしかめたり入力履歴をイベントの並びとして読み込んだりするためのプロトコルを持っている。
  • サブシステムへのアクセス−サブシステムはSmalltalkの中の独立したオブジェクトとして組みいれられている。Smalltalkの大きな懐にたよることができるし、ユーザーとの対話をふくむものはユーザーインターフェイスの中の構成部品にもなれる。
  • デバッガ−Smalltalkのプロセッサーの状態はスタックの連なりをもったProcessクラスのインスタンスとしてアクセスすることができる。デバッガは単なるSmalltalkのサブシステムであり、一時停止したプロセスの状態を変更できるものにすぎない。Smalltalkでおこりうる実行時のエラーはほぼただ一つ、メッセージを受け手が理解できないというものだけだというのは特筆に価する。

Smalltalkにはそうした意味での「オペレーティングシステム」は無い。ごく基本的な必要な操作、例えばディスクからページを読み込むといったものは、通常のSmalltalkメッセージに対応するプリミティブメソッドとして組みこまれている。


^

これから


予想されるように、Smalltalkプロジェクトではまだやらなければならないことが残っている。説明しやすいところでいえば、この記事で紹介した原則をさらに追究し、適用していくことだ。たとえば、Smalltalk-80システムはファクタリングの面ではまだまだで、というのもピラミッド型の継承しかサポートしていないからだ。Smalltalkシステムは将来このモデルを一般化して任意の(多重)継承をサポートするだろう。また、メッセージプロトコルも定形化されていない。Smalltalkシステムは種々のプロトコルを定義しているが、今のところ、あるクラスと別のクラスでプロトコルが一貫しているのはスタイルの問題にすぎない。これは適当なプロトコルオブジェクトを定義して、現在の言語のモデルを補完することで解決できるだろう。

残されたほかの課題については、はっきり説明するのがちょっと難しい。人間の思考にはまだ解明されていない側面があるはずで、現在のモデルを補完できるようなメタファーとして特定しなければならない。

時として計算機システムの進歩がうつになるほどのろのろしたものに思えることがある。でも私たちの祖父母の時代には蒸気エンジンがハイテクだったのだ。私は今の状況にかんして楽観的だ。計算機システムは実際にシンプルになりつつあり、結果、もっと使えるものになりつつある。終わりに、この過程を支配している一般的な原則で締めくくろう:

自然淘汰:良い設計の言語とシステムは生き残り、さらに良いものでおきかえられる

計算機は今しも刻一刻と進化している。助けはこちらに向かっているのだ。


^

BYTE Magazine, August 1981. Reproduced and translated by pron without permission.
(c) by The McGraw-Hill Companies, Inc., New York, NY.
All rights reserved.

Based on the paper scanned in and converted to HTML (with recreated graphics) by Dwight Hughes.

Link to this Page:  Squeak Tweak
Comanche5.0 / Swiki1.3 modified by pron[->?], thanks to..