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

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

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

（強調はあたし）

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

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





アプローチ1 取りあえず、本書にしてはめずらしく大きく外している（部分で抜き出しても有害さを説明しやすい）、 クラスの説明の部分を抜き出してみます。 この間違ったクラス説明をするために、OOPL以前の言語についての説明もワザとおかしくなっています。クラスの説明が間違っているから、「パッケージ」が OOP だとかよく解らないことが書いてあります。 「進化したOOPの仕組み１―パッケージ」は、わかりやすくオレオレでしょ？ 先ほどは「まとめる」仕組みとしてクラスを紹介しました。このパッケージは、そのクラスはさらに「まとめる」仕組みです。

* * *

この本における、クラスに説明は以下のようになっています。 クラスは「まとめて、隠して、たくさん作る」仕組み 1) サブルーチンと変数を「まとめる」

2) クラスの内部だけで使う変数やサブルーチンを「隠す」

3) 1つのクラスからインスタンスをたくさん「作る」 一見よさげに見えますが、ここが歪みの震源地。かなりまずい説明です。この歪んだ土台に論理を構築すると、どうなってしまうのかを見てみましょう。 「まとめる」の部分は具体的には以下の様に記述してあります。 クラスは、変数とサブルーチンをまとめたものです。

ここでいう変数とはC言語やCOBOLなどにおけるグローバル変数のことです。 グローバル変数とサブルーチンをまとめる？この説明を「OOPならでは」にするため、3章「OOPを理解する近道はプログラミング言語の歴史にあり」で過去のプログラミング言語について説明する際、ちょっとした「嘘」が入ってます。 構造化プログラミングでは解決できない2つの問題が残りました。それはグローバル変数問題と貧弱な再利用です。 モジュールを黙殺しちゃってるんです。*1 たとえばC でも 翻訳単位をモジュールと見立てて、関数（サブルーチン）と変数を まとめたり、変数や関数の名前のスコープを限定したりすることは当たり前に出来て、「まとめて、かくす」は 普通にやっています。 そこら辺に感じやすい人（Cを使いこなしている人）が、本書の OOP を OOP だと信じると、上記で引用したクラスの定義の内、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とは無関係に)発明した 「オブジェクト」（と「クラス」）です。これらの箱を用いて 責務分散協調系 としてプログラムを描くのがオブジェクト指向プログラミングです。 オブジェクトは小さな完結したコンピュータ。一つ一つのオブジェクトは 小さな責務をもっていて、プログラムが何か機能を果たすときには、これらオブジェクトが自身の小さな責任を果たしつつ協調し、系全体でその責務を果たします。（これらをケイは 細胞と組織に喩えました。）

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



