オブジェクト指向でなぜ作るのか を買ってみました

オブジェクト指向をわかりたいなら今すぐ『オブジェクト指向でなぜつくるのか』を読め -思っているよりもずっとずっと人生は短い。 VS お勧め本? - カレーなる辛口Javaな転職日記 について、http://www.kt.rim.or.jp/~kbk/zakkicho/08/zakkicho0807c.html#D20080728-4 さんよりお呼びが掛かりました。

普段、さんざ召還魔法を使いまくっている私としては、ここは恩返しのしどころです。けれど、敵はあまりに強大で...。


オブジェクト指向でなぜつくるのか―知っておきたいプログラミング、UML、設計の基礎知識―

オブジェクト指向でなぜつくるのか―知っておきたいプログラミング、UML、設計の基礎知識―



結論から先に言えば、OO の入門書としては、本書はダメです。ただ、なぜダメなのかを説明するのが難しくって。たとえば、はてブのyuguiさんのコメントみたいに

引用元の「憂鬱本みたいな感想」を読んだらこの本の悪い点は分かった。だが、学習ルートとしてはどうするのが良いんだろう。「良書」で初心者に分かるのはあるだろうか。

はてなブックマーク - お勧め本? - カレーなる辛口Javaな転職日記

(強調はあたし)


「みえる」「そこっ!」みたいな感じで問題点がわかってしまうと言う、端から見るとまるでニュータイプ(^^; な人向けに書くのは出来そうなのだけれど、ただ、それを解らない人(つまり、OOの入門書を必要とする人)に納得頂けるように 「○○だからこの本は良くないよ」と説明するのは非常に難しいです。

たとえ話で恐縮なのですが、間違っているとは言えないけれどゆがんでいるものを積み立てて行ったら、明後日の方向に積み上がってしまった・・といった感じですので、部分部分を抜き出しても駄目なところがわかりにくいし(むしろ正しいことが書いてあるように見える)、かといって筋道をたてて指摘をしだすと、OOPの本が一冊書けてしまうような感じなのです。むー、困った。

アプローチ1

取りあえず、本書にしてはめずらしく大きく外している(部分で抜き出しても有害さを説明しやすい)、 クラスの説明の部分を抜き出してみます。

この間違ったクラス説明をするために、OOPL以前の言語についての説明もワザとおかしくなっています。クラスの説明が間違っているから、「パッケージ」が OOP だとかよく解らないことが書いてあります。

「進化したOOPの仕組み1―パッケージ」は、わかりやすくオレオレでしょ?

先ほどは「まとめる」仕組みとしてクラスを紹介しました。このパッケージは、そのクラスはさらに「まとめる」仕組みです。


* * *


この本における、クラスに説明は以下のようになっています。

クラスは「まとめて、隠して、たくさん作る」仕組み

1) サブルーチンと変数を「まとめる」
2) クラスの内部だけで使う変数やサブルーチンを「隠す」
3) 1つのクラスからインスタンスをたくさん「作る」

一見よさげに見えますが、ここが歪みの震源地。かなりまずい説明です。この歪んだ土台に論理を構築すると、どうなってしまうのかを見てみましょう。

「まとめる」の部分は具体的には以下の様に記述してあります。

クラスは、変数とサブルーチンをまとめたものです。
ここでいう変数とはC言語COBOLなどにおけるグローバル変数のことです。

グローバル変数とサブルーチンをまとめる?この説明を「OOPならでは」にするため、3章「OOPを理解する近道はプログラミング言語の歴史にあり」で過去のプログラミング言語について説明する際、ちょっとした「嘘」が入ってます。

構造化プログラミングでは解決できない2つの問題が残りました。それはグローバル変数問題と貧弱な再利用です。

モジュールを黙殺しちゃってるんです。*1

たとえばC でも 翻訳単位をモジュールと見立てて、関数(サブルーチン)と変数を まとめたり、変数や関数の名前のスコープを限定したりすることは当たり前に出来て、「まとめて、かくす」は 普通にやっています。

そこら辺に感じやすい人(Cを使いこなしている人)が、本書の OOPOOP だと信じると、上記で引用したクラスの定義の内、1) と 2) は OOP とは関係成しに出来る部分であることに気がつきます。そうすると今まで無かった部分と OOP ならではの部分に線引きして、「そうか!OOPってこういうコトなんだ」と、新たな OOP を発見しちゃう訳です。

たとえばコチラ。疑りぶかいあなたのためのオブジェクト指向再入門

世間の入門書では、オブジェクト指向といえば「カプセル化」「継承」「ポリモルフィズム」ということになっていると思いますが、実のところカプセル化なんてオブジェクト指向とは無関係に昔から行われてきたことですし、継承やポリモルフィズムは、 必ずしも最初に覚えなければならないことではありません。(中略)

私は、オブジェクト指向の「本質」と呼ぶべきものは、カプセル化でも継承でもポリモルフィズムでもなく、「マルチプルインスタンス」にあると思っています

疑りぶかいあなたのためのオブジェクト指向再入門

自然な帰結ではありますが、でも、これって既に OOP でもなんでもないですよね?

前橋さんが なぜオブ本を見て上記記事を書いた訳じゃないのですが、多分 なぜオブ本を読んで飲み込んじゃった人は、前橋さんの記事に納得しちゃうんです。

一見正しそうにみえていながらゆがんでいる説明を土台に、そこから思考を進めるとカオティクに歪みが拡大していくという、だから「読むべきじゃない」本かな〜、と。


* * *


余談ですが、OOPにおけるクラスは、

  • オブジェクトの処理の移譲先 & オブジェクトのファクトリ

と捉えるべきだと思います。そういうことが出来る道具か否かは別として、少なくともOOPの理解において、クラスを「変数とサブルーチンをまとめたもの」と捉えるのは あまり美味しくありません*2。あー、でもクラスそのものの構造のメタファとしては捨てがたいのはわかるのです(が私は害のほうが大きいとおもうけれど、微妙)。どうしたもんかしら。

アプローチ2

この本のゆがんだところは なにも独創的なものではなくって*3、よく目にする説明です。先ほど引用させていただいた 前橋さんのドキュメントと、本書は、とてもよく似た香りがしますが、それはこの手の間違いがとても巷にあふれているためで、それ以上の関連はないです(多分)

この手の本の問題点として本質的なところは、OOPL の機能とか、OO関連技術とかは説明するのですが、肝心の、OOP によって作られたプログラムがどの様な姿をしているかを、イメージがつきやすい形で書いてくれていないことだと私は思います。

「どんな感じになるの?」というイメージもつかめずに、ただひたすら構成要素を積み上げていけば自動的に目的地に到達できる・・なぁんてことは出来るはずもなく、道からそれても気がつかずに明後日の旅路へついてしまいます。



さて、案の定というべきか、本書で枕として紹介されている「構造化プログラミング」についても同じように間違えています。こちらの方がOOPよりも小さいボリュームで説明できそうなので、これをモデルケースに この本のおかしさの説明を試みます。


* * *

基本的な考え方は「正しく動作するプログラムを作成するためには、わかりやすい構造にすることが重要である」というものです。
具体的な方法として、プログラムを解りづらくしている元凶であるGOTO文を廃止して、ロジックを順次進行、条件分岐、繰り返しの3つの構造だけで表現することを提唱しました。

前半はよさそうですが、後半は・・・ちっがーう! GOTO文があるからプログラムが解りにくいんじゃないです。だからGOTO文を排除しただけで(3大制御構造のみで記述しただけで)プログラムがわかりやすくなるんじゃないです。

GOTO文を廃止し、三大制御構造だけで制御フローを記述するのはなぜかというと、それはアルゴリズムを切り出して部品化を行う為です。GOTO文は飛び元と飛び先を含む部分を丸ごと一塊として扱う以外に手はありませんが、連接(concatenation)、選択(selection)、繰り返し(repetition) は、入り口が一つに出口が一つの構造なので、切り出しが容易です。


ダイクストラさん曰く、「良いプログラムとは正しく動くだけでなく、 正しく動いていることが容易に解るプログラム。」であるわけで、一方でテストで正しさを証明するのは原理的に難しいため、コードの可読性を上げて「正しく動いていることが容易にわかる」ようにしようというのが、構造化プログラミングの動機になります。

そんなわけですので、理想はコードをパパっとみればササッと正しく動くこと(あるいはバグがあること)が解るようなプログラムですが、しかしそれを実現するためにネックがあります。それは人間の能力不足です。具体的には規模への脆弱性で、人はただ数が多いだけで何がなんだかよくわからなくなってしまうのです。 だからプログラムの「難しさ」が同じ程度でも「規模」が大きくなるだけで、 とたんに人間の管理能力の限界を超えてしまい、プログラムを読んでも 「正しく動くこと」を理解できなく成ってしまいます。

そんなヘタレ人類に残された最後の(?)武器が抽象化です。抽象化することで見かけの規模を減らすことが出来るため、この技を使えば 人間の理解の脆弱性を補うことが出来ます。(なのでプログラミングに限らず、日常生活でも我々は抽象化をつかいます)

構造化プログラミングはソフトウェアの抽象化技法です。プログラムに段階的詳細化する構造を持たせ、ある階層からみればその下の詳細は抽象化されるため、規模の問題を回避できるのです。

構造化プログラミングを使って作成された プログラムは、丁度技術書のような章や項で構造化されたドキュメントとよく似た姿に描かれます。この構造の箱として「関数」がつかわれ、そしてそれらの箱の中を十分に小さい規模に保つことで、人間が簡単にプログラムの正しさを読み取ることができるようになるわけです。(関数の中身は小さくしろ、というのはこういう訳)

だから、十分に小さい箱の中であれば、別に goto文を使おうが、構造化プログラミング的には無問題です(だからC のは 箱の中にしか飛べない制約が掛かった goto文でしょ?)。途中リターンも同様です。


* * *


可読性を上げることでプログラムの品質を上げるというアプローチは、ソフトウェア工学の基本であり、OOP もこの基礎の上に立脚しています。そして、OOPも 構造化プログラミングと同じ ソフトウェアの抽象化技法です。

じゃあ、OOPと構造化プログラミングって何が違うの?、ですが、乱暴に言って以下の二つになります。

  • 構造化につかう箱が違う(関数→オブジェクト)
  • 部品のつなぎ方が段階的詳細化じゃない

OOP に使う「箱」は、Simula が(OOPとは無関係に)発明した 「オブジェクト」(と「クラス」)です。これらの箱を用いて 責務分散協調系 としてプログラムを描くのがオブジェクト指向プログラミングです。

オブジェクトは小さな完結したコンピュータ。一つ一つのオブジェクトは 小さな責務をもっていて、プログラムが何か機能を果たすときには、これらオブジェクトが自身の小さな責任を果たしつつ協調し、系全体でその責務を果たします。(これらをケイは 細胞と組織に喩えました。)


まー、よーするに、ただまとめただけじゃいかんのです。抽象化せにゃな〜。(と格好良く往ってみるテスト)

この本はダメな本なのか

とまぁ、ダメなところをあの手この手で説明しようと試みてきましたが、この本が本当にダメな本かというと微妙です。この本がターゲットに挙げているひとかた

ソフトウェア開発現場に直接関わっていないIT業界の管理職の方

のように、自分が技術者でないという認識がちゃんとある方には、それほど毒にはならないんじゃないかな、と思ったり。ライトなOO本にしてはアンバランスに低レベルに踏み込んだ章が用意されているのは、昔 C をやっていて、今は現役を退いて管理職になったような方を想定されているように思えますし。JavaBlackさんの「この本を読んでも作り方は解らん」に誰かが「『なぜ作るのか』だからそれでいいじゃん」と突っ込んでた、そういうのでよけりゃ、血にも肉にもなりませんがどうぞ、という感じ。

但し、本書がターゲットに挙げている残りの二つ、

初心者の方やオブジェクト指向に一度はチャレンジしながら挫折してしまった方

日頃からUMLJavaをつかってソフトウエア開発をしている方にとっては、自分が使っている技術の位置づけや目的を再確認するため

については、 私もJavaBlackさんの意見同様 OOPの理解を阻害する遅効性の毒が含まれていると思います。

本書はどう読んだって技術書じゃありません。正確に情報を伝えること・理解することは二の次で、飲み込みやすいことのほうを優先して書かれています。もちろん技術書であっても「入門書」ではこの傾向がみられますが、本書は入門書と呼ぶには 正確に伝えることに頓着しなさすぎで、結果「理解」することは叶わず、飲み込むしかないのです。(だからこそ、飲み込みやすいといえます)

これは 憂鬱本のような「(今となっては)間違い」とかじゃなくって、もう、確信犯ですから、だからダメ、と評価できない。ややこしいなぁと思います。










・・・・・って、ホントにそうかな。この本、本当はものすごくヤバい本じゃないのかな?

というのも、私もこの本読んで相当混乱させられて。ここはよし、ここもまぁいっかな?と確認しながら歩いているのに、気がつけば明後日の方向にいる。それが実に巧妙で、この本には方向感覚を狂わせる魔法か何かが掛かっているのでしょうか、と思うくらい。なんか階段を上ったつもりなのに気付いたら降りてる感じですよ。気付いたら迷ってます。この本には見た目のフレンドリーさに反した、なにか恐ろしいものの片鱗を感じるのですが、それが何だか説明できない...orz 魔書?。パウ・デイレルの書とか、その類の本?


細かい項目のそれぞれが、一見まっとうなこと書いてあるように見えて実は微妙に本質を外してる、でも間違ってるとバッサリするには躊躇する――そういうのばっかりで。確かにそこだけ抜き出しても間違いと言いきれないけど、ていうか間違いがコンテキスト依存してるから抜き出し指摘が意味をなさないあたり質が悪すぎですし、でも、そういう小さいゆがみでも、全体を組み上げるとなんか OO が別物になってるから、「いいんじゃん」と言うわけにもいかないというか。

で、比較的大きめにハズしている クラス周りにドライバをつっこんでこじ開けてみたのだけれど、それでもそれに対して何かを書けば書くほど、自分が明後日の方向に爆進しているイヤンな感触が強くなる。「そういうお前がオレオレだ」臭がでてしまう。あたしがダメか、ダメですかorz。


・・・らめぇっ、こんなの無理。何度も何度も書き直したけれど、全然上手く掛けないよー(T△T この本が良いと思えてしまう人にダメと納得できるように説明するのは、あたしには無理です。誰か書き直してー。

とりあえず、腕に覚えがある方はこの本を買って、恐ろしさの片鱗を味わうことをおすすめします。

*1:ここだけを抜き出せば、「構造化プログラミング」と限定されちゃえば間違いと言うのは無理になるんですが(^^; もともとこの章の趣旨「OOPL発生までの歴史を追ってOOPを理解する」からすれば、間違いと言ってしまって良いと思います

*2:もっと余談ですが「変数とサブルーチンをまとめたもの」は、クラスの出自である Simula的にも嘘になります。Simula 67 のクラス/オブジェクトは、Algol 60 のブロック(Cのブロックとだいたい同じ)を拡張したもので、「存在し続けるブロックの実例」がオブジェクトであり、その元となる手続きがクラスになります。(って、ダールのじっちゃが言ってた。)

*3:ということにしておこう。ホントのところ、ちょっとほかに見ないほどのオレオレ定義をギュギュっと拘束着の下に押し込んでいる風に感じてます。

限りなき旅は続く

余談です。大変失礼ながら、「オブジェクト指向でなぜ作るのか」の最後のページ、「作者プロフィール」をみて、笑ってしまいました。*1

それから、「現実世界をそのままソフトウエアに表現するオブジェクト指向技術」を求めて10年余りの旅に出るが、当初の目標を達成出来ずに終わる。その経験を元に本書を執筆する。


というのも、この興味深い旅路の軌跡を、目にしたことがあるからです。

オブジェクト指向は本当に「オブジェクト」指向か?

3.1 多重分類と動的分類

実は現在主流となっているオブジェクト指向プログラミング言語にはある制約があります。それは「オブジェクトが帰属するクラスは唯一で、かつ帰属するクラスを変更することができない」というものです。あまり一般的な用語ではありませんが、前者を単一分類 (single classification) 、後者を静的分類 (static classification) と呼びます。

つまり会社員、学生をクラスとして定義した場合には、ある人が会社員になったり、学生になったりすることをオブジェクト指向プログラミング言語では直接表現できないのです。

オブジェクト指向は本当に「オブジェクト」指向か?

4.2 オブジェクトの世界は階級社会?

ところで英語のclassには「階級」という意味もあります。オブジェクトの世界も、クラスを「分類」ではなく「階級」と考えると、少し違った様子に見えてきます。

つまりオブジェクト指向プログラミング言語の世界では、そこに住むオブジェクトの階級 (class) は、オブジェクトが誕生した時点で唯一に定まっており、この世から消えるまで決して変えることができないのです。これではまるで中世の封建社会のようです。中世の国王にとっては、その方が国の秩序を保つのが簡単だったように、私たちモデラーにとってもオブジェクトの階級が決まっている方が、ソフトウェアの秩序を保つのが容易なのかもしれません。

将来的にはもしかすると、オブジェクトが自律的に動き回り、自由に成長していくようなプログラミング言語が登場するかもしれません。しかしそんな世界をどうやって分析・設計すればよいのでしょう?むしろそのときには、民主社会に国王の統治が要らないように、オブジェクトの世界を完全に操る私たちモデラーも不要な存在になってしまうのでしょうか?

オブジェクト指向は本当に「オブジェクト」指向か?

なるほど、何処か遠いところに旅だってしまったようです。(^^;


平澤氏のこの記事については オレオレOO以外の何者でもなく、失礼ながら私も、

  • あたった文献が悪いのでは?(笑) オブジェクト指向アプローチなる語を「間違った定義」をしてる文献ばかりにあたってしまったとか?
オブジェクト指向は本当に「オブジェクト」指向か?-Wiki っぽい場(あるいは 疑似脳内ネットワーク)

という事じゃないかな〜、、と思います*2

このような壮大な旅の結果、平澤氏がたどり着いた結論は、オブジェクト指向と現実世界は大違い」です。(重い、重いわ)

なので、

歴史に「れば、たら」は禁物ですが、もし「クラス」ではなく、集合論をイメージしづらい「モジュール」などの別の名前がつけられていたら、ソフトウェア開発技術の歴史は大きく変わっていたかもしれません。

には、つい、「オレも惑わされることなかったのに、とほほ」という、穿った見方をしてしまいます。


この本が正しく見える理由

この本が正しく見える理由は、2章にあります。平澤氏が壮大な宇宙旅行の末たどり着いた結論は、さすがに威力絶大ということでしょうか。

で、これまでよく言われていた「間違ったOOP」を説明してみせながら、

で、ちゃぶ台をひっくり返してみせます。

  • クラスとインスタンス、継承に関する勘違い
  • ポリモーフィズムに関する勘違い
  • 現実世界をそのままソフトウェアに表現しない
  • 現実世界との対比はたとえ話として割り切るのがコツ

正しく間違いを指摘しているから 正しいというわけじゃないのですが、でもそうであるとその論調すべてが正しく感じるというモノ(マインドハック?)。それに加えて、「現実世界との対比はたとえ話として割り切るのがコツ」という言には、平澤さんの魂の叫びを感じまするるる、なので、間違いの指摘に実体験を伴った言葉の重みがにじみ出てしまっていて余計読者に 本書が玉石混合混交の「玉」であると思わせてしまうのだと、私は思うんです。

*1:て、最後のページから読むと...なあたりが、また「パウ・デイレルの書」ぽいです、とラノベオタクなアタシは思ってしまう

*2:で、軌道修正できたか、歴史が繰り返しているか、というのが本書を巡る争いのキモと言うことで(^^;

駄目なOO本の見分け方?

正しいアプローチは 良書を読む・・ということなのですが、なにが良書かを判断するのは難しいです。なぜオブ本や憂鬱本が良書として紹介されているのですから、Web の書評の多数決もあんまりあてにならないです。

なので、せめて駄目なOO本の見分け方をちょこっとだけ書こうと思います。とはいっても、毒キノコの見分け方 並にナンセンスな話なので、眉に唾を付けて読んでいただけると幸いです。


OOP とは 「カプセル化」「継承」「ポリモルフィズム」である、という説明(いわゆるオブジェクト指向3点セット) を是としていたり、議論の土台においてある本は ダメだとおもったほうが無難です。

「オブジェクト指向プログラミングとは何か?」[Stroustrup87] (PDF, ただし '91 改訂版) - Smalltalkのtは小文字です に詳しいのですが、これはもともとこれだけの言語機能があれば オブジェクト指向プログラミングをその言語上で実践できると、C++ の作者が定義したもの が伝言ゲームを起こしたモノです。

抽象データ型に加えて、以下の機構がオブジェクト指向プログラミングをサポートするのに必要とされる。

  • 特殊な関数呼び出し機構(仮想関数、動的結合)
  • 型チェック機構
  • 継承機構
  • 多重継承機構
  • アクセスコントロール機構

以上は5点ですが、ここから静的型言語(あるいは C++ )に特異的な3点(型チェック機構、多重継承機構、アクセスコントロール機構)が拒絶されて「抽象データ型+ 継承・動的結合」となったのち、「カプセル化、継承、多態性」に変化して定着したものと思われます。

「オブジェクト指向プログラミングとは何か?」[Stroustrup87] (PDF, ただし '91 改訂版) - Smalltalkのtは小文字です


これらの機能を満たさない OOPL も非常に多いですし、これらの機能があれば OOP 出来る、というだけで機能そのものがOOPなわけではないのです。

OOP だとか 構造化プログラミング だとかいった プログラミング技法は、その技法によってシステムをどの様な姿に描き出すかが重要で、そのための道具に何があれば可能か(あるいは便利か)を列挙しても、その技法そのものを説明するには足りません。

そういうところを意識しないで、「三大」を 「OOP とは」の説明に使っているものは、駄目な本でしょう。(「OOP」 と 「OOPLでできること」 をゴッチャにしてる)たぶん。