物のない生活

(翻訳)



過去数年間、私は多くのプログラミング言語の研究と実験に費やしてきました。 特に、私はScalaをメイン言語として使い始めました。可能な限り機能的なスタイルを使用しようとしています。 Haskell(純粋な関数型言語)とClojure(現代のLisp方言)にも非常に興味がありました。



このように、私は主に過去17年間の私の専門的活動を使用したという事実にもかかわらず、オブジェクト指向のパラダイムを徐々に放棄しました。 私は、オブジェクトが、私たちがラピッドで構造化された再利用可能なコードを書くことを妨げるものであると感じています。





このトピックについて考えるとき、私は私の思考に急激な変化がなかったことを理解しています。 施設の利点は、時間の経過とともに徐々に低下しています。 私が今オブジェクトを使用する方法は、私が若くて素朴なときに使用した方法とは大きく異なります。 この投稿では、OOPの理解におけるこれらの変化を明らかにしたいと思います。



OOPの約束



90年代初頭、施設は新しく、興味をそそられるものでした。 この新しいパラダイムの支持者は、再利用可能なクラスとパターンを作成する可能性を約束し、魅力的に聞こえました。 これらのクラスを再利用可能でカスタマイズ可能なビジネスコンポーネントに結合する機能は、ソフトウェア業界の聖杯のように思えました。 C ++以降のJavaなどの新しい言語の開発者は、クールなソフトウェアを作成する方法としてOOPのプロモーションをサポートしています。



ビジネスコンポーネントは再利用できません


再利用可能なビジネスコンポーネントを作成する機能が誤りであることがすぐに明らかになりました。 1つの業界であっても、すべてのビジネスは他のすべてのビジネスとは異なります。 同様の各プロジェクトは、非常に具体的なビジネスロジックで機能します。



このレベルで再利用可能なビジネスコンポーネントを作成する唯一の方法は、ルールエンジンや埋め込み言語などを追加することで、それらを非常にカスタマイズ可能にすることです。 このようなモデルをコンポーネントモデルとは呼びません。 むしろ、ブロートウェアの次のインスタンスのモデル。 再利用の約束はなくなり、人々は巨大なブロートウェアシステム(敗者)を購入するか、独自のプロジェクトで独自の特別なビジネスオブジェクトを開発しました。



パターンで構造化ソフトウェアを作成しないでください


次に気付いたのは、デザインパターンへの期待が満たされていないことです。 パターンは良い構造につながりません。 それどころか、それらはプログラムの過度の複雑さ、コードの理解の困難さ、およびメンテナンスの高コストにつながります。 一部のパターンはアンチパターンにさえなりました(たとえば、シングルトンパターンでは単体テストを作成できません)。



プログラマーがパターンを有意義に使用することを学んだのはごく最近のことです。 モデルを自分で理解する方法でコードを書く方がはるかに簡単です。 そして、それをアレクサンドレスクの本の一般的なパターンに抽象化しようとしないでください。



クラスとコンポーネントのフレームワークは、再利用にはあまり効率的ではありません。


オブジェクトパラダイムのもう1つの約束は、互いに一緒に使用される密接に関連するクラスの開発されたフレームワークです。 このパラダイムは、再利用可能なコンポーネントからアプリケーションの構築を大幅に簡素化することを約束し、実装の技術的な困難と微妙さを完全に隠します。 EJBのようなものを意味します。 ただし、これらのフレームワークは機能しないことが経験からわかっています。 それらは大きすぎて、人々がやりたいことをするのを妨げます。



このような重いフレームワークはすぐに消滅し、より軽量のライブラリと軽量ライブラリのセットに置き換えられます。 密接に関連していないクラスのセットからプログラムを構築する方が簡単であることが明らかになり、ニーズに応じてまとめることができます。 異なるクラスを密接に統合する必要はありません。



継承は脆弱なソフトウェアにつながります


インターフェイスと実装を継承する機能は、OOPの主要な原則の1つです。 共通のコードと動作を基本クラスに区別できますが、将来の抽象化ではこのコードを使用し、それに基づいてロジックを追加できます。



残念ながら、これは機能しません。 各サブクラスは、その親とわずかに異なります。 これは、子クラスに多くの変更をもたらします。 または、基本クラスをより一般的にしようとします。 壊れやすいコードになってしまいます。 基本クラスのわずかな変更が、生成されたクラスのすべてではないにしても、ほとんどのクラスの内訳につながります。



カプセル化違反


OOPのもう1つの基本原則は、状態をカプセル化し、状態を操作するための動作メソッドを提供する機能です。 残念ながら、ほとんどの場合、オブジェクトデータ全体が必要であり、それらを操作する方法は必要ないことが判明しました。



たとえば、オブジェクトにHTMLでのレンダリングを依頼するのはばかげています。 この場合のHTMLのレンダリングに関する知識はプロジェクト全体に広がっており、レンダリングコードの小さな変更は多くのクラスの変更を伴います。 オブジェクトをHTMLレンダリングの個別のコンポーネントに渡す方が適切です。 そして、このコンポーネントはまず、オブジェクトから関心のあるすべての値を抽出します。



さらに、動作メソッドなしでカプセル化された状態のオブジェクト(Java Bean、データ転送オブジェクトなど)を作成できるアンチパターンもあります。 そのようなオブジェクトを作成する場合、なぜオブジェクトの代わりに構造を使用しないのですか?



可変状態-問題の原因


カプセル化のもう1つの明らかな利点は、このオブジェクトを使用するコンポーネントに影響を与えずにオブジェクトの状態を変更できることです。 ただし、大規模なオブジェクト指向プロジェクトの開発者は、オブジェクトの状態がエラーに変わる場所を見つけるために膨大な量のコードを列挙することについて話をすることができます。オブジェクトの状態)。



不変の状態およびステートレスサービスに関心を示すほど、そのような問題はないと確信します。 不変の状態のもう1つの利点は、並列システムを作成して最新のマルチコアプロセッサを使用する効率を向上させることです。 これは、ストリーム、ロック、およびスレッドセーフなデータ構造を操作するよりもはるかに簡単で正確です。



物のない生活



だから、あなたの17年の経験を捨てて、物のない人生について考えることは可能ですか? この点で完全な啓発に到達したかどうかはまだわかりません。 しかし、Scalaマルチパラダイム言語を使用すると、OOPの多くの制限を回避できます。



たとえば、Mixin Traitsなどの機能がScalaに存在すると、実装の継承を完全に放棄できます。 不揮発性の値とコレクションを使用すると、コードの理解とデバッグが容易になります。

動作を拡張するための一般化された抽象化や型クラスなどの関数を使用すると、適切に構造化され再利用可能なコードを作成できます。 この場合の単一責任の原則は完璧です。



実際、ケースクラスの形式で単純なオブジェクトを使用してデータ構造を表現しようとしていることに気付きました。 そのようなクラス用のメソッドはほとんどありません;それらはデータの処理を容易にすることのみを目的としています。 関数をグループ化するには、mixin特性を使用します。 私が設計するコンポーネントは、データをある形式から別の形式に変換するさまざまな関連機能を単に収集します。



おそらく、私は思っているよりも純粋なOOPからはるかに進んでいるのでしょう。 これまでよりもコンパクトで理解しやすく、構造化されたコードを書いていると自信を持って言えます。



(翻訳者のメモ:この記事では、経験豊富なOOPプログラマーのOOPに対する態度に焦点を当てたいと思います。私はScala言語、したがってScala固有の用語に精通していません。



経験豊富なプログラマーがOOPに失望していることについて話す状況がますます増えています。



Scalaの可能性について。 どうやら、彼らは本当にOOPに対処しなければならないケースの全範囲をカバーしています。 ErlangまたはHaskellの機能がこれを悪化させないことを付け加えます。




All Articles