2016年05月12日

オブジェクト指向と戦った戦士達の軌跡

Qiitaでオブジェクト指向と戦った人たちの記事が10年単位で語られてて、twitterで話題になってますね。



そうか、30年も戦うと何か変な悟りを得るのか・・・

かくいう俺も今の職場に配属されてからそろそろ10年、オブジェクト指向と戦ったといえなくもない微妙な経験を積んだので、一度頭を整理する意味でもオブジェクト指向について整理してみよう。



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

オブジェクト指向とはなんぞやという質問に対する回答ですよね。
10年戦士の人はカプセル化だけが重要だっていってるし、
20年戦士の人は
  • カプセル化
  • ポリモーフィズム
  • データ抽象
  • 継承
の4つだって言ってるのかな、いや、そもそもオブジェクト指向と世間で呼ばれているもの自体が4種類あって、
  • クラス指向
  • インタフェース指向
  • オブジェクト指向
  • メッセージパッシング指向
って言ってるのか・・・これもうわかんねぇな。

俺の考えとしては、世間で言われてるオブジェクト指向の最大公約数的な要素はおそらくポリモーフィズム
メッセージを処理するオブジェクトの中身によって、同じメソッドでも違う動作を行うのであればそれはオブジェクト指向だ。

file.save(); // ファイルの中身を保存する
record.save(); // DBのレコードにデータを保存する

これが呼び出す場所によって異なる動作をするようだと、それはアスペクト指向と呼ばれる別のパラダイムになる。

file.save(); // 通常の呼び出し場所であれば、save()の前後にログを出す
file.save(); // エラー時であればログを出さずにsave()する

最近聞かないねアスペクト指向。典型的な用途はログ出力だけどそれ以外有効な活躍場所がなかったから廃れてのか。
そりゃログのためだけに新しいパラダイム適用するとかオーバースペックもいいとこだもんな。

とにかく、操作対象(ここではオブジェクトと呼ばれる)によって同じメソッド、もっと言えば同じ関数名でも異なる名前空間のものが呼びだされますよ、というのがオブジェクト指向の真髄なんであって、これをメッセージパッシングとか仮想機械とか大げさな用語で語るからいらん混乱を招いているんだと思う。

現実的な方向性が見えてきたオブジェクト指向

そんな風にポリモーフィズム以外の特徴はあったりなかったりで何が正しいのかよくわからなかったオブジェクト指向言語たちなんだけど、最近は実用的に使うための機能が整理されてきて、どの言語もみんな似たり寄ったりになっているように思える。
具体的に言うと
  • 継承
  • 静的型
  • 無名関数と関数オブジェクト
こんなもん。若干関数型言語からの輸入があるような。。。まあ流行りだからね。

継承の概念はクラスの概念がほぼ前提になっている。クラスを使わないプロトタイプベースオブジェクト指向言語だったjavascriptは激しく使いづらかったらしくて、ついにES2015でクラスと継承を取り入れた(もっと前バージョンからあったっけ??)Java、C++、Ruby、Pythonには古来から存在してた。

静的型は多人数でコーディングする場合、問題を関数呼び出しの段階で解決できるようにするためのチェック機構として優秀だ。このためjavascriptやrubyでも静的型を導入しようという言語拡張が幾つかあった(Typedホニャララとかいうやつは大抵コレ)けどあまり広まってない

なんでかというとおそらく副作用の方が多いからなんだろうな。たとえばシェルスクリプトみたいな個人用ツールに静的型を導入すると型宣言のタイプ時間だけでストレスがマッハになるし。というわけで同じMS謹製の言語でもC#は静的型あり、Powershellは静的型なしでいってるんだろうけど。

あ、でも単にタイプがめんどいだけなら型推論でなんとかなるのかな。ここらへん導入したLLってあんま聞いたことないから気になる。

無名関数と関数オブジェクトについてはこれ完全に関数型言語からの輸入だよね。rubyがブロックとして他に先駆けて導入してから流行った感がある。あまりにも強力。こいつの導入によってデザインパターンのうちいくつか(Command、Iterator、ひょっとするとBridgeも)は不要なものになっちゃう可能性がある。つーかデザインパターンって今考えると柔軟性の不足しているJavaやC++でやりたいことをやるために多大なコード量をつかって無理に設計レベルで対応を行っていただけで、実際には言語自体の機能不足を補うものだったのかもしれない。

あとはあれかな。Java以外の言語はプロパティ記法もだいたい標準装備になってきたよね。まあいちいちゲッターセッター書きたくないもんね。 ・・・いかん、どんどん単なるJavaの悪口になってきた。生まれた時期が古いだけで素直ないい子なんですよJava(唐突なフォロー)
あとリフレクションとメタプログラミングもかなり一般的になってきたと思う。ただし黒魔術すぎてみんなが使うのは危険な気がするけど。

また一方で各言語に導入された珍奇な機能のうち、よその言語に伝播せずに消えていった一発屋機能たちもいっぱいある。

好例がC++のテンプレート。こいつもメタプログラミングの一種なのかもしれないけど主な活躍場所はコレクションクラスにおけるジェネリクスだった。つまりListクラスだけじゃListの中に何でも入れられて型安全が破壊されるのでList<String>クラスを作るみたいな。そのためだけにマクロの親玉みたいなあの機能を入れるのはオーバーキルだったんじゃないですかね・・・マクロといえばLispが本場だけどあれもどの言語も採用しないじゃん、一般人には到底扱いきれないんだよマクロとその仲間たちって。

それと関数型言語からいろんな概念が導入されてきたけど、カリー化、メモ化、モナドあたりは波及しなかったね。リストの内包表記もここに含めてもいいかもしれない。Python付近にちょっとだけ導入されたみたいだけど。
関数型言語で使われてる技術って、どれもこれも洗練されてて数学的に美しい!みたいな機能満載なんだけど、残念ながらプログラムってどっちかというとドキュメントであり過去の事務手続きの遺産を継承できたほうがいいねみたいな文献学的な要素のほうが大事なんで、概念が美しくても過去のものが使いやすかったら取って代わるようなことはできなかったんだと思う。
例えばカリー化で異なる引数の実装を流用するほどならオーバーロードやらデフォルト引数使う方がわかりやすいよね。
メモ化も専用の機能提供しなくても、副作用を許す言語ならハッシュテーブルとかに普通に値をキャッシュしていけばいいよね。
モナドは、、、ちょっとよくわからん。あれ何のために必要なの?状態遷移をどっかの領域にまるっと保持しといて引数から戻り値にバケツリレーしてるだけのように見えるけどそれ臭いものに蓋してるだけなんじゃ(まだ理解不足)

徐々に設計の話にうつるオブジェクト指向

10年戦士も20年戦士も最後の章はわずかに言語の話をそれて、設計論に近いことを言うようになってる。そもそもオブジェクト指向って設計よりに近い概念だからなのかもしれないけど。
カプセル化が複雑な部分を隠蔽して利用者に単純な操作だけを提供するものっていうのは正しい。MVCにおけるFat Controll問題にも通じるんだけど内部のごちゃごちゃした実装はオブジェクトならprivate領域、MVCならモデルで隠蔽されるべきなんだろう。その意味ではrailsの都合とはいえevalファミリーで中をごちゃごちゃにいじれるrubyは設計者の敵とも言える。あれ普通の頭の人間がちゃんとメンテできるのか。

あと再利用がファンタジーにすぎないっていう話もよくわかる。特に継承による再利用ってまず使えないものしか出てこないんだよな。ぎりぎりあるとすればフレームワーク側で抽象クラスが定義されてて利用者はドキュメントに基づいてクラスを具象化してくださいねって言う使い方のアレ。JavaでいうとJFrame。
んで、実際にJFrameで作って動いているGUIアプリを更に継承してもう一つ複雑なGUIアプリを作れるかというと無理。無理やり複雑な継承関係を実現すると大抵これ使いたいんだけどどのクラスから継承すればいいんだっけみたいな疑問ばっかり出てきて使いづらい。
つまり具象クラスはこれ以上継承しちゃいけないんだろうな。

ここまで話を進めていって、最初の章で話したオブジェクト指向とはなんぞやという話題がなぜ何年も何年も繰り返されるのかが少しわかった気がする。オブジェクト指向って言語機能じゃなくて設計思想側に重点が置かれている概念なんで、それぞれのオブジェクト指向言語に機能の共通点があんまなくても設計の課題とかで共通のくくりで語ることができるんじゃないのか。なのにそもそもオブジェクト指向とは何かを語るとき、やれ継承だ、クラスだ、ポリモーフィズムだなど言語機能のことが頭に登ってくるのでみんな混乱すると。ちなみにカプセル化はちょっと設計よりだね。

最後に

サマリーにも書いたけど30年戦士の人はどうしてこうなった。rubyに縛られて過ごすのが嫌になったか
あるいはひねくれ性格だからちょいと逆張りパワーワード言いたくなった?(もしかしたらこれが正解かも)
posted by LoyalTouch at 22:10| Comment(0) | TrackBack(0) | プログラム全般 | このブログの読者になる | 更新情報をチェックする
この記事へのコメント
コメントを書く
お名前:

メールアドレス:

ホームページアドレス:

コメント:


この記事へのトラックバック