8/02/2020

OOPに対する問題は誇張されている

Young Coderより(M)。

50年経った今でも、私たちはプログラミングの支配的なパラダイムについて混乱しています。

マシュー・マクドナルド

何人かの敵を引き付けなければ、開発世界を何十年も支配することはできません。そして、オブジェクト指向プログラミングは、新旧数十種類の言語の概念的基盤を提供していますが、確かに敵もいます。

そのためか、私たちはOOPについての終わりのない一連のホットテイクに苦しんでいる理由です。彼らはOOPを、生産性を破壊する災厄であるとか、一連のごまかしのプログラミング・パターンであるとか、貧しいプログラマが無能さを隠すために設計された平凡なツールであるとか説明してきました。OOPは死んだとさえ宣言されたことがありました(14年前ですので、割り引いて下さい)。

OOPの4つの柱

これらすべての暴言に共通しているのは、現代のソフトウェア設計の落とし穴のいくつかを(正しく)指摘し、これがプログラミング世界の中核にあるひどい腐敗を示していると(間違って)結論付けているいるということです。確かに、オブジェクト指向プログラミングは、ずさんなデザインやや曖昧なアーキテクチャ思考と混同してしまうと、それほど素晴らしいものには見えません。しかし、これらの愚行は本当にOOPの避けられない部分なのでしょうか? それとも、自信過剰で好奇心旺盛なプログラミング初心者の私たちが迷い込んでしまう間違った道の1つに過ぎないのでしょうか?

原罪

問題は、一部のOOP支持者とその批評家のほぼ全員が行っている1つの脆い思い込みから始まります。OOPは、現実世界をモデル化することを目的としているということです。これはOOPの原罪であり、無数の肥大化したコードベースの原因となっている腐った考えです。

OOP理論には、オブジェクトをプログラミングして現実の世界に対応させる必要はありませんが、多くの善意のある教師が、新入生の複雑さの曲線を下げるためにこの考えを使っています。Oracleの公式Javaドキュメントにある問題の図です。

「オブジェクトは、オブジェクト指向技術を理解する上で重要です。今すぐ周りを見渡して下さい。現実世界のオブジェクトの多くの例があります。犬、机、テレビ、自転車など。ソフトウェア・オブジェクトは、概念的には現実世界のオブジェクトと似ています。」

これは例外ではありません。多くの入門書では、車と車輪のオブジェクトの例を示したり、個人と家族オブジェクトを絶望的に結び付けたりして、コードの構造と実世界のオブジェクトの間の境界を曖昧にしています。それは狂気の沙汰です。

この考えは、オブジェクト関係マッピングを使用してデータベースをリンクされたクラスの霧の中に爆発させるようなアンチパターンにもつながります。

この種のデザインは誰にとっても間違っているわけではありません。しかし、ORMシステムに手錠をかけられ、必要以上に複雑で効率が悪いデータクラスのボイラープレートを延々と生成している不幸な人たちがたくさんいます。OOPはこれを奨励していたのでしょうか? そうかも知れませんが、本当の原因は、すべての識別可能なものは、それ自身のオブジェクト表現に値するという考えが行き詰まってしまったことです。

デザインは、オブジェクト・モデルの完全性ではなく、コードのニーズによって導かれるべきであるということ忘れてしまうと、良いことは何も起こりません。

オブジェクトのより良い説明は、多くの正直な答えと同様に、少し曖昧なものです。それは次のようなものになります。

オブジェクトとは、データと機能をある程度まで再利用可能なパッケージにまとめることができるプログラミング構造です。一部のオブジェクトの中には、別の名前の構造になっている場合があります。その他のオブジェクトは、単に関連する機能のライブラリである場合があります。プログラミングの問題をどのようにオブジェクトに分解するかを決定することは、OOPの技術の一部です。

そして、常に洞察に富んだEloquent JavaScriptより。

「何かがオブジェクトのように聞こえるからと言って、それが自動的にプログラムの中でオブジェクトであるべきだということを意味するわけではありません。アプリケーションのすべての概念に対して反射的にクラスを書くことは、相互接続されたオブジェクトの集合を残す傾向があり、それぞれが内部で変化する状態を持っています。このようなプログラムは多くの場合、理解するのが難しく、簡単に破棄されてしまいます。」

経験豊富なプログラマは、オブジェクト指向性の低いソリューションとよりオブジェクト指向性の高いソリューションのどちらかを選択する場合、プロジェクトのニーズを満たす最もシンプルなアプローチを選ぶべきであることを理解しています。

デザインは難しい

もし、OOPが正しく実行するのが難しいとしたら、使用するツールに関係なく、少なくとも一部には、ソフトウェア・デザインが正しく実行することが難しいためです。

実際、OOPは、多くの人々が信じているよりも、デザインにおける規定がはるかに少ないのです。オブジェクト指向言語は、オブジェクトを使用するための一連のツールを提供しています(インタフェースとの相互作用の形式化したり、継承を使ってオブジェクトを拡張するなど)。しかし、これらのオブジェクトをどのように問題に適用するかについてはあまり言及されていません。これは大きな意図的な曖昧さです。

理論と実践のギャップが、デザイン・パターンへの関心を煽りました。OOPがより一般的になるにつれ、プログラマはそれらのアーキテクチャの支援を求めました。残念ながら、デザイン・パターンは、過度に複雑なOOPデザインを、信頼性という名の下に、密かに持ち込む方法になりがちです。

この罠をどうやって避けますか? 頻繁に頭字語で引用される優れたプログラミングの堅固な原則に焦点を当ててみましょう。DRY(Don't Repeat Yourself)、YAGNI(必要のない機能なら作るな)、デメテルの法則(クラスがお互いについて知っておくべきことを制限する)、継続的なリファクタリング、そして何よりもシンプルさと読みやすさを重視するといった原則が含まれます。これらの堅固な原則、つまりコーディングの哲学から始めて、その環境でデザインを具体化していきましょう。

継承の期待のミスマッチ

OOPに対する最も鋭い攻撃の中には、継承を標的にしたものがあります。批評家は、子クラスとその親クラス間の微妙な依存関係によってコードベースが時間とともに凍結されてしまうという、極めて本質的な脆い基底クラスの問題を指摘しています。

脆い基底クラスの問題や他の継承の二日酔いに対する解決策は驚くほどシンプルです。使うな。あなたが聞いたすべての戒めとしての話は真実です。

継承が意味をなすのはフレームワークの設計、言い換えれば、使用するツールを構築する人のためのツールとしての継承です。.NETやJavaのクラス・ライブラリは、厳密な継承階層がなければ、はるかに貧弱で整理されていない場所になってしまうでしょう。しかし、このタイプのフレームワークの作成して維持することは、大規模なアーキテクチャ上のタスクです。動きの速い顧客中心のアジャイル開発者チームであれば、あなたがやりたい類のことではありません。そして、ここに汚い秘密があります。最初に何度か間違ったことをしない限り、おそらく正しく理解できないでしょう。

オブジェクト指向プログラマの仕事の初日

つまり、継承は、間接的に使う場合は素晴らしい機能ですが、自分のクラスを拡張するために使う場合は、殺鼠剤を2乗したように有害です(rat poison squared)。そして、あなたはそれを必要することさえありません。機能を再利用したいのであれば、包含(containment)と委譲(delegation)が完全に機能します。また、様々なクラスを標準化する必要がある場合、それがインタフェースの目的です。

ここで、OOPの本当の限界が見えてきました。OOPは、問題に対して間違った解決策を適用することを防ぐことはできません。厳しい締め切りの前や、空腹のワニの隣など、窮屈な隅で設計するのを防ぐことはできません。あなたが楽しむことも、誤用することもできるツールセットを与えてくれます。後はあなた次第です。

OOPに対する批判はありますが、おそらく真実でしょう。OOPは死んだわけではないかも知れませんが、世界が完全に支配していた時期は消えつつあります。関数型プログラミングはOOPとともに成長し続けています(しかし、非難はなかなか始まらないものですが)。そして、純粋なOOPは、GoやRustのようないわゆるマルチパラダイム言語(オブジェクト指向機能のよりスリムなセットを備え、従来のOOPのお荷物の一部を回避する言語)へと移行しつつあります。今後10年の間に、これらの言語が本当に始まったのかは、開発者自身のテイクダウンに取り上げられているのを見た時に分かります。それまでは、OOPを楽しんで、コードをクリーンに保って下さい。

Hacker News