Adult-Oriented Punk!

+ オブジェクト指向について徒然

last mod.2020/05/08 

2006/12/15
2010/3/10 更新
2012/7/27 まくらのまくらを追記
2013/2/6 getter/setterの話の具体例となっていた日記ページがあったので、リンクを追加した。
2014/11/12 Stateパターンについて書いたページのリンクを追加


私はもともと(1990年代)、オブジェクト指向の超信者でしたが、現実の仕事で机上の空論が使えない状況に直面し、挫折しました。しかし何とか使える方法があるはずだ、とさらに勉強して、「オブジェクト指向は使いよう」で、危ういが有効な道具だと思い至りました。

そんな折、

仕事上で「それはちょっと違うんじゃないの?」というようなオレ流オブジェクト指向をごり押しされていやな思いをしたことがありました。
「彼」はどうやら雑誌や教科書でオブジェクト指向を知り、盛んに周りの作業者に自分の知識を広めているようですが、その知識を実際に適用して成功したとか失敗したとかそういう経験に基づいた話が一切ないので、私は眉に唾して聞いていました。
プロジェクト終盤にて、「彼」がかかわった箇所は速度性能が要件を満たさないわ、納品直前だというのにcore吐きまくるわ、ひどい有様で、早い時期に彼の「ご高説」と袂を分けたウチのチームが要件の9倍の性能を出して落ち着いていたのとは対照的な状況でした。

ちょっと時間ができたので、学生時代に学んだこと、仕事を通して実感したことを踏まえ、自分が考える「オブジェクト指向」について、メモしてみます。

ところで、定義するという英語(de-fine)の語源は、端(fine)を決める(de)、ということだそうです。何かを定義するということはつまり、それがどこからどこまでなのか、何であって、何でないかを線引きすることである、ということです。

オブジェクト指向とは何か、という解釈が、十人十色どころか十人二十色になることは、承知しています。


私の解釈はこうです。
オブジェクト指向は、複雑な問題を細分化するための一つの方法の案です。問題の細分化作業は具体的には、共通性でグループ化したあとに、そのグループ中での可変性を調べることを、全体が良く整理できるまでやり直し繰り返すことです。その共通性・可変性の分析の際、プログラムの機能のまとまりにばかり目を向けず、データのまとまりにも同じように目を向けようという提案です。

これはソフトウェア工学(大規模ソフトウェアが妥当なコスト内で機能要件・性能要件を満たし、製造したソースリストが可読性、可変更性、可管理性の高い状態を保つにはどうすればいいか)の解を探る中で、歴史的に機能分割がうまくいかなかった状況に対し、なんとかそれを打破しようとする想いから発生したものです。

オブジェクト指向が主に焦点を当てたのはソフトウェアの設計であり、プロジェクトのマネジメントには言及していません。
また、発生当初は計算機科学者の「ソースの字面上、なんか面白そう」というような興味本位な気持ちが、推進力のかなりの割合を占めていただろうと考えています。

(私の非難対象のひとつはコレ)

You meet: Smalltalk and: [You feel: better].
Smalltalk say: 'simple, pretty, neat' to: you.


Smalltalk関連の書籍で見た「定義」はこうでした。

オブジェクト指向言語とは、下記を満たすプログラミング言語。
  • (1) オブジェクトの型を定義できる
  • (2) オブジェクトの動きを定義できる
  • (3) オブジェクトを生成する文を記述できる
  • (4) オブジェクトに計算をさせる文を記述できる

興味深いのは、この定義ではいわゆる「新しいオブジェクト指向言語」だけではなく、例えばCやPASCAL、もっと言えばFORTRANやCOBOLも含まれてしまうことです。しかし私はこの定義に賛成します。上記以外は本質(ソフトウェア工学の解を見出す)に対して瑣末なことだと考えるからです。

ただ、その本質論はちょっと保留して、「瑣末」といって切ってしまった部分、「新しいオブジェクト指向言語」の要素をメモしてみます。

  • (a) オブジェクトの継承の仕組みがある
  • (b) オブジェクトの型と動き(プロパティとメソッド)を同列に論ずることができる
  • (c) プロパティやメソッドについて、公開、隠蔽のレベルわけができる
  • (d) ソースの字面上、"オブジェクト 作用子 プロパティ" あるいは "オブジェクト 作用子 メソッド" という記述を用いることができる

大きな問題を細分化する際「小さなことには目をつぶり、エイヤーで大雑把に把握できるようにする」ことを可能にする、という考え方がほぼ低通していると考えます。

(a) -> 小さなことに目をつぶりたいからです。
(b) -> "論ずる"とは具体的には、設計を考えるときに同列に考えることができる、ソースに記述できる、などです。機能による問題分割とデータによる問題分割のねじれを防ぎ、俯瞰をわかりやすくしたいからです。
(c) -> 情報隠蔽やカプセル化といわれる内容です。小さいことに目をつぶりたいからです。
(d) -> 作用子とは スペース、"."、"->" などの終端記号です。オブジェクト指向以前のプログラムソースで "機能 作用子 データ" と記述していたことに対し、逆転の発想を求めたかったのです。おそらく。






単刀直入に。私は、「フレームワーク」という言葉が一般的になった後と、その前とで、オブジェクト指向は大きく2分割できると考えます。

古いオブジェクト指向:
一部の学者の単なるアイデアレベル。
「大規模プロジェクトをどうにかまとめる」ことは目標の一つだったが、まだ実現する方法は確立してなかった。
いわゆる「機能分割」をやめさせるために、センセーショナルな言い回しをつかって説明していた。
オブジェクトの切り出しは「現実にあるモノのとおり行う」が金言だった。
継承の説明といえば差分プログラミングだった。

新しいオブジェクト指向:
「フレームワーク」と、それを構成する「コンポーネント」としてのクラス分割が一般的になった。
インタフェース継承をうまく利用し、ミドルウェア的な基底クラスを設計することにより、複数のアプリケーションを構築する際に統一性の縛りをかける技法が広がった。
特徴的なクラス構成を(ソフトウェアの)「デザインパターン」と呼ぶことが定着した。
データ継承等、初期には継承で上手に実現できるとされた一部の共通化技法は、テンプレート等、継承以外の技法で実装することが多くなった。

参考:memo/20051221 カーギルとウォルドの多重継承は要るか要らないかの議論の話。

今も昔もオブジェクト指向で変わらない本質はいくつかあると思います。そのひとつが下記です。

【オブジェクト指向技術の本質的な目的は、上手に「抽象化」して、高いレベルで語ることができるような手段を提供すること】

これを前提とすれば、細かすぎるクラス分割はオブジェクト指向の本質から外れる、という命題が導けます。

当然、程度問題です。
ベテランにしかわからない構成では問題ありですし、1年目の新人(または新規参入者)にわかりやすい構成でも、問題ありです。

「犬猫レベルのサンプル」とは:
雑誌記事に載せることができる程度の小さなサンプルプログラムで、オブジェクト指向の本質を語るには小さすぎるもの。

小さすぎるサンプルとして、動物クラスを継承した犬クラスや猫クラスが鳴いたり食べたりするものがある。
自分もこのようなサンプルを使って他人に説明したことがあり、反省しています。

学校を出て、現実問題への対処とオブジェクト指向を考えるにつれ、オブジェクト指向と非オブジェクト指向のメリット・デメリットを語るには、最低でも2キロステップ程度のサンプルが必要ではないかと考えるようになりました。より適切なのは5キロ程度と考えます。

ソフトウェア設計論で犬猫レベルの説明を持ち出すことは、ジャンボジェットの設計に昆虫の飛行理論を持ち出すようなものだと考えます。いくつかの原理は使えるし思わぬひらめきが生まれるかもしれないけど、縮尺が違うので専門家にとってはほとんど別の問題だということ。






getter、setterは、必要なのか?

私は、getter、setterが、本当の意味でのソフトウェア工学の目的(大規模ソフトウェアを、期限・性能・予算を満足し完納する)に寄与した場面を、見たことがない。自分が見たことがないものを存在しないというつもりはないが、控えめに言って、本当に存在するのか?と疑問視している。

現場では、オブジェクト指向を、「単なる技術者の満足・遊び」ではなく、「ソフトウェア工学の解の可能性の一つ」として利用しているはず。
ソフトウェア工学が問題にするのは大規模ソフト開発での責務完遂であって、中・小規模はあまり重要でない。

大規模ソフトの開発プロジェクトでは、チーム間のインタフェースは問題になりやすいことを皆知っているので、
  • 先にインタフェースを決めてから中身を作るようにしたり、
  • 公開インタフェース一覧の文書にバージョンをつけて管理したり、
  • 公開インタフェースの変更の手順を決めたり
して、インタフェース齟齬の問題を防ぐ。
そのような手法は、オブジェクト指向を声高に叫んでいないチームでも昔から実践していたのを見たし、オブジェクト指向を声高に叫ぶプロジェクトでも、大して違いはないように見えた。

またインタフェース齟齬の問題は、例えばデータ保持クラスの全データに対して、ご丁寧に getXXXXX、setXXXXX を定義することでは、絶対に解決しない。

私は、データメンバ一つ一つに対するgetter、setter は、オブジェクト指向やソフトウェア工学の本質ではなく、不要のものと考えている。

追記:memo/20111206 に、getter、setterの良い例、悪い例を書きました。

シングルトン = 結婚しないかもしれない症候群、ブリジッドジョーンズの日記 等

シングルトンパターンはGoF本のパターンの中でも特に理解が容易。初学者は無意味にシングルトンパターンにしたがる。GoF本には、世の中で流行っているコトバの力を借りて論文にインパクトを出そうとした罪があると思っている。

シングルトンパターンに意味があるのは、
「ソースを公開せず、ライブラリだけを」
「お金の流れが違う他のチームに提供し」
「そのチームがライブラリの間違った使い方をしたことによるバグと、その解析に付き合わされることを避けたい」

場合には使える。
それ以外なら、単にドキュメントに「このオブジェクトはプロセスでただ一つだけ生成してください」と書いて、それを説明するだけ。

ご大層な仕組みをつくっているが、本当に「使える」場面は、極わずかしかない。

一方で、GoF本の中でも理解しやすいパターンなので、初学者が「オレ、デザインパターン知ってるよ、シングルトンていうのはね~」などとご高説を披露することになる。やれやれ。

私は「シングルトンパターン」を使おうとする技術者には、本質を理解しているのか?というフィルターをかけて接するようにしている。




Stateパターンが活きるのは、少なくとも、

  • 目的を実現する機構を、状態遷移機械もしくは有限オートマトンとして設計した
  • メッセージ数がとても多い
  • 状態によって、受信者にとって関心のあるメッセージがガラッと変わる
  • 状態によらず、送信者はメッセージを出しつづけたい

の全てを満たす場合、だと考えます。

+ Stateパターンについて