2012/07/06

自由なプログラム

こんにちは、このブログがウクライナやラトビアで大人気なようで有頂天になっている@tomoodaです。 いつもプログラミングの技術についてなんだかヘンテコな理屈をこね回してばかりなんで、今回は技術というより楽しさみたいな話をしてみます。

オレはブルックススキーなんで、ソフトウェアについて考える時にはいつもブルックスがソフトウェアの4つの本質的困難として掲げた複雑性や同調性、可変性、不可視性を基準として考えを纏めるようにしています。これらの本質的困難というのは、実はソフトウェアの楽しさの裏返しにもなっています。つまり、複雑性は複雑なものを組み上げて動かす楽しさ、同調性はレゴや機械をうまく制御したり人間と調和して対話する楽しさ、可変性は既にあるゲーム等を改造して遊ぶ楽しさ、そして不可視性は物体としての実体がないことの楽しさ。ん?物体としての実体がないと何が楽しいんだろう?もうちょっと掘り下げてみましょう。

ソフトウェア以外に、物体としての実体がないのにアレコレできて楽しいものって、どんなものがありますかね?1つは魔法の呪文です。世界中いろいろな所に魔法の物語があります。イギリス発の魔法学校の物語があったり、日本にも魔法少女のアニメがいっぱいありますね。あれって、なんで楽しいんでしょう?たぶん、物体としての実体がないからこそ、どんな魔法でも創造できちゃうんですね。だから楽しいんですよ。魔法学校の話のほうなんて、もう状況設定からして荒唐無稽で支離滅裂。そんな伝統社会の常識からの自由があの作品の面白さなんですよ。常識からの自由、物理的実体からの「自由」が魔法の呪文の根底にあると思う訳です。

昔、呪文が本気で信じられていた時代もありました。その頃は、呪文は「実体がないのに面白いもの」ではなく、まさに物理世界の根源と思われていたのだろうと思います。その時代の呪文は、実体がないという不可視性よりも森羅万象との同調性が重視されていたのではないでしょうか。話はちょっと横道に逸れてしまいましたが、ようするにソフトウェアの不可視性からくる楽しさというのは、魔法の呪文をつくるような楽しさがあるし、同時に魔法の呪文と同様に物理的な物体を動かしたり人間にイタズラできたりする。プログラマは現代の魔法使いなのだと思います。

不可視性の楽しさの根底にあるものを「物理的実体からの自由」と書きましたが、これこそオレがソフトウェアに惹かれた原点でもあります。小学生の頃、友達から「ハムやらない?」と誘われたのがそもそもの発端。そこから電子工作の楽しさに取り憑かれました。それまでは自宅の1Fの町工場で材料と工具を借りてベニア板とか鉄線とかで工作するのが趣味だったのが、ベニア板や鉄線では滅茶苦茶難しそうなことが、トランジスタやICを線でつなげるだけで実現できる。LEDが生き物みたいに光って動く。そして部品屋(浜松のマルツ電波)に入り浸るようになって、マルツの1Fでマイコンに出会ってしまった。MZ-80Bと書かれた小さなテレビで、ハンダ付けしなくても鳥がパタパタと羽ばたいている。何十行ぐらいの英語みたいのを入れると、動くらしい。まさにこの瞬間、この少年の将来の職業が確定しました。ツ

というわけでオレがプログラミングをはじめたのは「物理的実体からの自由」だったわけですが、ソフトウェアにまつわる自由は物理的実体だけじゃなくて、色々あるわけです。フリーソフトウェア、つまり政治的自由を求めるソフトウェアなんかは代表例ですね。フリーソフトウェア運動がプログラマから出てきているという歴史的経緯から言っても、ソフトウェアって、色々な意味で本来自由なものなんだろうな、ソフトウェア作りに身を投じている人は結構な割合で自由に惹かれてきたんだろうな、と思う訳です。

その一方で、静的型付けだとか、契約プログラミングだとか、形式手法だとか、プログラムに対する厳格な制約を適用する技術も沢山あります。これらは一見すると自由を制限するようにも思えるかもしれませんが、実際にはこれらは「この制約を守る限り、自由にやっていいよ」という自由裁量を確保するための技術とも言えます。つまり、「どうやって実現するのかという方法の自由」です。方法の抽象化と呼んでもいいかもしれません。指定された制約を守ればよいということは、つまり、「ここは、こうに決まってるだろ、業界の常識だぞ?」とか「実はお客さんにこういう提案しちゃったから、この実装じゃ駄目だよ。」みたいな暗黙の制約を排除して、プログラマの書きたいように書いて楽しむ事ができるわけです。自由を満喫しましょう。

では動的型付けはどうでしょう?もちろん、これもやはり自由のための技術という説明ができます。動的型付けが実現しようとする「極限までの遅延」とはつまり、「極限まで実装を選択する自由を残す」ということです。ある式を評価する時の具体的な実装コードを、まさに評価している最中にまで保留して、実装コードからくる制約をできるかぎり遅延させて、自由でいられる時間を引き延ばしています。動的型付けもやはり「どうやって実現するのかという方法の自由」を実現するための技術なのです。自由っていいですね。

最近ではVMで動作するプログラム処理系が増えてきました。これもやはり計算機械という物理的実体を抽象して自由を確保するための技術です。計算機械は、1つ1つの機械語のインストラクションが駆動します。プログラムを書くということは、計算機械に適切なタイミングで適切なインストラクションを供給することです。計算機械は物理法則で動いています。プログラミング言語の大切な機能は、この「計算機械」を抽象することです。物理法則で動く計算機械を抽象することで自由を確保することです。そしてVMというアーキテクチャはその抽象をアーキテクチャで実現しようというものです。

計算機械を仮想化することで物理的実体から自由になるという意味では、仮想化サーバやクラウドコンピューティングもやはり同様ですね。JS上でLinuxが動きました、なんて話を聞いてワクワク楽しい気分になるのは、やっぱりCPUやOSに縛られない、自由だからという要素もあるかもしれません。

もう、いっぱいありすぎて、1つ1つ挙げていったらキリがないです。でもこれは当然のことです。あのブルックスさんがソフトウェアの本質とまで言っていることなのだから。オレの狭い了見で書いたこの駄文だけではほんの氷山の一角です。他の3つの本質的困難についてもやっぱり沢山あると思います。複雑性のほうは、もうこれこそがソフトウェア工学の華といってもいい分野ですね。個人的には、ソフトウェア工学は複雑性に集中しすぎてないかな、という印象があって、でも最近はUIとかUXとかアジャイルとかTDDとか、他の3つの本質的困難=本質的楽しさに切り込んでいく分野も出てきていて、どんどん楽しくなってきました。

ブルックスさん自身が語るプログラミングの楽しさについては、この抜粋がわかりやすいです。さすがです。オレなんて、これをプリントアウトして会社のキャビネに貼ってます。どうです、オレってスイーツなブルックス信者でしょ?

で、結局何が言いたかったかというと、なんで「楽しさ」について書こうと思っていたのに、気付いたら技術のことばかり書いちゃうのかなー、ってことです。シ

2012/06/16

何も隠されてはいない

こんにちは、あまりにも更新が少ないんで、そろそろこのブログも存在を忘れられつつあるのではと憂慮している@tomoodaです。 今日のダベりネタは情報隠蔽です。

オブジェクト指向といえば情報隠蔽によるモジュール化という説明を見かけるたびに、「オブジェクト指向は何も隠してなんていないのに」と思ったりします。 以前、クラス/インスタンス関係と型/値関係をゆる~くしてみようで、オブジェクト指向は分類学じゃないよ、クラスはオブジェクトを分類するんじゃなくて、振る舞いを分類しているだけなんだよー、とか書いてみました。 まあオレが言うことだからあんまり信憑性ないかもしんないけど、情報隠蔽についてもなんだか誤解が多いなあと思ってます。

まずは、クラスはインスタンスの分類じゃなくて振る舞いの分類なんだよ、を振り返ってみましょう。

例えば、悪名高い、動物の例。動物クラスと犬クラスと猫クラスがあります。 これらのクラスは個々の動物を犬とか猫とか動物に分類するんじゃないんです。 個々の動物の色々な振る舞いを列挙してみましょう。 散歩したり、マーキングしたり、ブロック塀に上ったり、フリスビーをくわえたり。 これらの振る舞いを、これは犬の振る舞い、これは猫の振る舞い、これは動物一般の振る舞い、と分類するんです。 それがクラスだと思うのです。

単に振る舞いをまとめただけだから、分類学じみたことなんて必要ないです。実装上の便宜で適当に決めていけばいいです。 実装継承バンザイ。いいんですよ、それで。

こう書くと、多くの人は「クラスが定義するメソッド(メンバ関数)はそうかもしれないけど、インスタンス変数(メンバ変数)はどうすんだ?あれはオブジェクトの構造を定義しているんじゃないのか?クラスがインスタンスの構造を定義しているんなら、クラスはインスタンスを分類しているんじゃないか!」と思うかもしれません。

ブッポ〜ン

まあ正当派のソフトウェア工学では、クラスはオブジェクトの構造を定義すると教えています。 そしてその根拠が抽象データ型です。 抽象データ型は値が持つデータ構造を手続き抽象によって隠蔽するという機構ですが、多くのソフトウェア工学の本ではオブジェクトは抽象データ型の実装の1つであると見なしているようです。

でも、残念ながら、オレオレオブジェクト指向では、オブジェクトは抽象データ型の実装ではありません。 全くの別物です。 では、クラスで定義するインスタンス変数(メンバ変数)が、抽象データ型で隠蔽されるデータ構造ではないのなら、一体何なんなんでしょう。

それは「振る舞いを実現する環境」です。 ここで言う環境というのは、クロージャに近いです。ネストした内側のクロージャが外側のクロージャのローカル変数を参照するようなものです。 別にオブジェクトのデータ構造とかじゃなくて、オブジェクトの振る舞いを実現するメソッドを実装するための環境なんです。

そう考えると、クラスというのはオブジェクトの振る舞いを分類して定義しているだけの話で、分類学的な整合性とかどうでもいいし、データ構造を隠すとかはどうでも良い話なのです。 オブジェクトの本質は、ユーザが認識した対象を捕まえて、そいつにメッセージを送って、そいつがメッセージに対して何らかの振る舞いをすることです。 つまり、データ構造を隠すも何も、データなんて最初からオブジェクト自身にとってはどうでもいいことで、大事なのはその振る舞いなのです。

つまり、オブジェクトは何も隠してなんていません。 少なくともSmalltalkでは。

次に、Smalltalkでは何も隠されていないどころか、全てが表現されるという話をします。

Smalltalkでは全てがオブジェクトだと言われていますが、実は、Smalltalkでもっと大事なのは、全てが評価可能な式として表現されることなのです。 これこそがSmalltalkをSmalltalkたらしめている所以です。

Smalltalkの素晴らしさは、そのダイナミズムにあります。できるかぎりあらゆる事が動的に決まります。 アラン・ケイ博士がいうところの「あらゆる事の、極限までの遅延」です。 そして、Smalltalkでのダイナミズム、すなわちワークスペースでの表現式評価も、クラス定義も、メソッド定義も、全ては「評価可能な式」として表現されます。 Smalltalk内で発生したダイナミズムは「評価可能な式」として表現され、記録され、そして実行されます。 「あらゆる事の、極限までの遅延」があるから、記録されたダイナミズムは再実行が可能になります。 そして記録されたダイナミズムがSmalltalk環境の再構築を可能にし、記録されたダイナミズムを別の環境で再実行することを可能にし、さらなるダイナミズムを生み出します。

どうですか? 本来のオブジェクト指向では「何も隠されていない」のです。 なぜなら、プログラマに全てを曝け出し、全てを分解することができ、全てを変更することができることこそがオブジェクト指向が本来目指しているプログラミングだからです。

つまり、隠したいプログラムがあったらオブジェクト指向言語はお勧めしません、というのが今日の結論です。ツ

2012/04/11

再利用をめぐるあれやこれや

こんにちは、ずいぶん久しぶりの更新のテーマは、再利用性です。

再利用性はソフトウェア工学永遠のテーマです。 再利用性は生産性を向上させるための必須項目とされています。 多くのプログラミング言語プログラミング環境が再利用性を謳い、それでいてその多くは話題から去っていきました。 たぶん、その言語や環境が提供する「再利用性」なるものが、多くの人にとって必要とされている「再利用性」とは異なっていたのでしょう。 その結果「もっと上流で再利用しないと、下流でだけ再利用しても効果がないよ」とか「それはツールがまだ揃ってないからだよ」とか、色々な枝葉が出てきています。 そこで、ふと思うのです。再利用って一体何なんだろう?再利用が向上させる生産性とは一体何なんだろう?

単純に考えれば、プログラミングにおける再利用性というのは、あるプログラムの構成要素を別のプログラムを構成するために流用することです。 関数であったり、述語であったり、オブジェクトであったり、クラスであったり、パッケージであったり、プログラムの断片だったり、色々な構成要素が再利用の対象になります。 ある関数を別のプログラムに流用する。簡単じゃん、どうしてみんなそうしないの?と思いますが、もちろん簡単じゃない理由があります。

全てのプログラムには、正常に動作するための条件が設定されています。CPUだったりOSだったりメモリサイズだったりネットワークだったり、色々な「環境」を前提にしています。 プログラムの構成要素にも前提条件があります。逆に言えば、前提条件に合致しない環境に流用しても正しく動作しません。 例えば、引数として整数を受け付ける関数に文字列を渡しても正常に動作しません。 静的型付け言語であれば型エラーや暗黙的型変換をするでしょう。動的型付言語だと動くかもしれませんし、動かないかもしれません。 この意味では、再利用性を高めるためには前提条件を少なくすることが必要だと言えます。 より正確に言えば再利用性を高めるためには前提条件を明確にすることが必要で、さらにその前提条件が少なければ嬉しい、ということになります。

その上で、前提条件を変更しやすいということが大事だと思っています。

単純な例として、ソートを挙げてみます。 整数の配列を引数として取って、その内容を小さい順に並べ直した配列を返す関数を定義してみます。 ここで再利用性を高めるために何が出来るでしょうか? 配列の要素の型を、整数だけでなく浮動小数点数や文字列など、他の型でも使えるようにすることも「前提条件の変更」です。 また、配列だけではなく、線形リストや木構造を引数として取る事が出来るようにすることも「前提条件の変更」です。 さらに引数が一度に与えられるのではなく、関数を評価している最中に引数の配列の要素が段々と埋まっていく、という環境でも使えるようにすることも「前提条件の変更」ですね。 もしかしたら、「大小関係」自体も最初から定義されているのではなく、ソート関数を評価している最中に1つ1つ例示しながら学習していく、というのも考えられます。 前提条件には、データ構造も制御構造もIOも問題定義自体も含まれます。 どれも変わるかもしれない前提条件なのです。

オレオレ哲学になっちゃいますが、世の中には通時的に必然的な正しさなど無いと思います。 何が正しいのかはその時やその場所によって移り変わっていく世界観や価値観で変わっていきます。 データ構造も制御構造もIOも問題定義も、どれも前提条件として変化していくものです。 一度書いたらあとは使うだけ、というのは幻想です。 書いたときには絶対に正しいと信じていた事が、後になって間違いに変化してしまうのが常です。

一度書いたら、次はもっと良いモノを書く。 それをやりやすいプログラミング言語、それをやりやすいプログラミング環境というのが、再利用性の高い言語や環境だと思います。

同じことが生産性にも言えます。 生産性とは何でしょうか? 多くの職業プログラマにとって生産性とは、単位時間に生産するコードの量でしょう。 同じ期間かけたらより多くのプログラムを書いた方が生産性が高いし、同じプログラムを書くのに必要な時間が短かくてもやはり生産性が高いと言われます。

では、再利用の視点で生産性が高いプログラマとは、過去に誰かが書いたコードを継ぎ接ぎしてコードを仕立て上げる能力が高いプログラマなんでしょうか? たぶんソフトウェア工学的にはそうなのでしょう。 でもそれってなんか違うと思うのですよ。 だって、プログラマは生ものですから。

オレには「ある問題を解決するためにプログラムを書いたら、次に問題を解決する時にはもっと良いプログラムを書ける」という信念があります。 逆に言えば、そうでなくなったらプログラマを引退すべきだと思ってます。 生産性が高いプログラマになるということは、大量のコードを書けるということではなくて、その問題を解決するためにより簡単に、より便利に、より納得がいく解決法としてのプログラムをサクッと書ける、ということだと思っています。 つまり、オレにとっての生産性とは、同じ時間でどれだけたくさんのコードを書けるかではなく、同じ時間でどれだけ賢くなれるか、ということです。

そうでも思わないと、別に賢くもないオレなんて、やってられませんよ。ツ