彼の懸念は、多数のクラスがメンテナンスの悪夢につながることでした。私の見解では、それはまったく逆の効果をもたらすだろうということでした。
私は絶対にあなたの友人の側にいますが、それは私たちの領域と私たちが取り組む問題やデザインの種類、特に将来どのような種類のものが変更を必要とする可能性が高いのかという問題かもしれません。さまざまな問題、さまざまな解決策。私は正しいか間違っているとは信じていません。プログラマーが特定の設計問題を最善に解決するための最善の方法を見つけようとしているだけです。私はゲームエンジンとあまり違いのないVFXで働いています。
しかし、少なくともSOLID準拠のアーキテクチャ(COMベースである)と呼ばれるもので苦労した私にとっての問題は、「クラスが多すぎる」または「機能が多すぎる」に大まかに要約されるかもしれません。あなたの友人が説明するかもしれません。具体的に言うと、「相互作用が多すぎる、誤動作する可能性がある場所が多すぎる、副作用を引き起こす可能性がある場所が多すぎる、変更が必要な場所が多すぎる、考えていることを実行できない場所が多すぎる」
いくつかのサブタイプのボートによって実装されたいくつかの抽象(および純粋な)インターフェイスがありました(ECSの利点について説明するコンテキストでこの図を作成し、左下のコメントを無視します)。
モーションインターフェイスまたはシーンノードインターフェイスは、ライト、カメラ、メッシュ、物理ソルバー、シェーダー、テクスチャ、ボーン、プリミティブシェイプ、カーブなど、何百ものサブタイプによって実装される可能性があります(多くの場合、それぞれに複数のタイプがありました)。そして究極の問題は、実際、これらの設計がそれほど安定していないことでした。要件が変わり、インターフェイス自体も変更する必要がありました。200のサブタイプで実装された抽象インターフェイスを変更する場合、それは非常にコストのかかる変更です。その間、抽象ベースクラスを使用することで、そのような設計変更のコストを削減することで、それを緩和し始めましたが、それでも依然として高価でした。
そこで、代わりに、ゲーム業界でかなり一般的に使用されているエンティティコンポーネントシステムアーキテクチャの調査を開始しました。これにより、すべてが次のように変更されました。
そしてすごい!それは保守性の点でそのような違いでした。依存関係は抽象化ではなく、データ(コンポーネント)に向かって流れていました。そして、少なくとも私の場合は、要件が変化しても、データははるかに安定しており、設計の観点から適切に取得するのが簡単でした(ただし、同じデータでできることは要件の変化に伴い常に変化しています)。
また、ECSのエンティティは継承ではなく構成を使用するため、実際に機能を含める必要はありません。それらは単なる「コンポーネントのコンテナ」です。これにより、モーションインターフェースを実装した200のサブタイプは、モーションコンポーネント(モーションに関連付けられたデータにすぎない)を格納する200のエンティティインスタンス(個別のコードを持つ個別のタイプではない)になります。A は、別個のクラス/サブタイプではなくなりました。クラスではありません。これは、空間内の場所(モーション)とポイントライトの特定のプロパティに関連するいくつかのコンポーネント(データ)を組み合わせたエンティティのインスタンスです。それらに関連付けられている唯一の機能は、システム内にあります。PointLight
RenderSystem
、シーン内のライトコンポーネントを探して、シーンのレンダリング方法を決定します。
ECSアプローチの下で要件が変更されると、多くの場合、そのデータで動作する1つまたは2つのシステムを変更するか、側に新しいシステムを導入するか、新しいデータが必要な場合は新しいコンポーネントを導入するだけで済みました。
したがって、少なくとも私のドメインでは、すべての人ではないことはほぼ確実です。依存関係が安定性(まったく頻繁に変更する必要のないもの)に向かって流れていたため、これは非常に簡単になりました。COMアーキテクチャーでは、依存関係が抽象化に向かって一様に流れていたときはそうではありませんでした。私の場合、モーションに必要なすべてのことよりも、前もってモーションに必要なデータを把握する方がはるかに簡単です。これは、新しい要件が入ってきて数か月または数年かけて少し変更されることがよくあります。
OOPで、SOLID原則の一部またはすべてがコードのクリーン化に役立たない場合はありますか?
まあ、きれいなコードはきれいなコードをSOLIDと同一視する人もいるので言えませんが、ECSのように機能からデータを分離し、抽象化からデータに依存関係をリダイレクトすることで間違いなく物事がはるかに簡単になる場合がありますデータが抽象化よりもはるかに安定している場合は、明らかな結合理由のために変更します。もちろん、データへの依存関係によって不変式を維持することは困難になりますが、ECSは、特定のタイプのコンポーネントにアクセスするシステムの数を最小限に抑えるシステム組織で不変式を最小限に抑える傾向があります。
DIPが示唆するように、依存関係が抽象化に向かって流れるとは限りません。依存関係は、将来の変更が必要になる可能性が非常に低いものに向かって流れる必要があります。それはすべての場合において抽象化であるかもしれないし、そうでないかもしれない(それは確かに私のものではなかった)。
- はい、SOLIDと部分的に競合するOOP設計原則が存在します
- はい、SOLIDと完全に矛盾するOOP設計原則が存在します。
ECSが本当にOOPのフレーバーかどうかはわかりません。一部の人々はそれをそのように定義していますが、私は本質的に、カップリング特性と、機能(システム)からのデータ(コンポーネント)の分離とデータのカプセル化の欠如と非常に異なっていると思います。OOPの形式と見なされる場合、SOLID(少なくともSRP、オープン/クローズ、liskov置換、およびDIPの最も厳密なアイデア)と非常に矛盾していると思います。しかし、これは、少なくとも人々が一般にそれらをより認識可能なOOPコンテキストで解釈するので、SOLIDの最も基本的な側面がそれほど適切ではない1つのケースとドメインの合理的な例であることを願っています。
小さなクラス
友人の驚いたことに、多くの小さなクラスといくつかの抽象化レイヤーを含むゲームのアーキテクチャを説明していました。これは、すべてに単一の責任を与え、コンポーネント間の結合を緩めることに集中した結果だと主張しました。
ECSは私の意見に挑戦し、大きく変えました。あなたのように、私は保守性の考えが可能なものに対して最も単純な実装を持っていると考えていました。これは多くのことを意味し、さらに多くの相互依存的なものを意味します(相互依存関係が抽象化の間であっても)。1つのクラスまたは関数のみにズームインして、最も単純で単純な実装を確認したい場合に最も意味があります。1つも表示されない場合は、リファクタリングし、さらに分解することもできます。しかし、結果として外の世界で起こっていることを見逃すのは簡単です。なぜなら、比較的複雑なものを2つ以上のものに分割するときはいつでも、それらの2つ以上のものは不可避的に相互作用する必要があるからです*(以下を参照)方法、または外部の何かがそれらすべてと対話する必要があります。
最近では、何かの単純さと、存在するものの数と、必要な相互作用の量との間にバランスのとれた行為があることがわかりました。ECSのシステムは、PhysicsSystem
やRenderSystem
などのデータを操作するための非自明な実装ではかなり重い傾向がありGuiLayoutSystem
ます。ただし、複雑な製品に必要なものはごくわずかであるという事実により、コードベース全体の全体的な動作を簡単に後戻りしたり推論したりする傾向があります。そこに何かがありますが、それは、より少ないかさばるクラス(依然としてほぼ間違いなく単一の責任を実行しています)の側に寄りかかることは悪い考えではないかもしれないことを示唆するかもしれませんシステム。
相互作用
抽象化を使用して2つの具体的なオブジェクトを切り離すことができますが、それらは相互に通信するため、「結合」ではなく「相互作用」と言います(相互作用を減らすことは両方を減らすことを意味します)。それらは、この間接的なコミュニケーションの過程で副作用を引き起こす可能性があります。そして、しばしば、システムの正確さを推論する能力は、「結合」よりもこれらの「相互作用」に関連していると感じます。インタラクションを最小限に抑えると、物事が鳥瞰図のすべてについて推論するのがはるかに簡単になる傾向があります。つまり、物事はお互いにまったく話していないことを意味し、その意味から、ECSはまた、最小限の最小値への結合だけでなく、「相互作用」を本当に最小化する傾向があります(少なくとも私は持っていません)
とはいえ、これは少なくとも部分的には私と私の個人的な弱点かもしれません。巨大な規模のシステムを作成し、それについて自信を持って推論し、ナビゲートし、予測可能な方法でどこでも潜在的な望ましい変更を行うことができると感じている最大の障害は、状態とリソース管理です副作用。数万のLOCから数十万のLOCから数百万のLOCに移行するとき、それは私が完全に自分で作成したコードであっても、発生し始める最大の障害です。何かが何よりもクロールを遅くする場合、アプリケーションの状態、データ、副作用の面で何が起こっているのか理解できなくなります。それ' システムが私の思考能力を超えて成長した場合、変更の完全な影響を理解することができないほど私を遅くする変更を行うのに必要なロボットの時間ではありません。インタラクションを減らすことは、私にとって、これらのことに圧倒されることなく、より多くの機能を備えた製品をより大きく成長させるための最も効果的な方法です。アプリケーションの状態を変更し、副作用を大幅に引き起こす可能性さえあります。
このようなものに変えることができます(ダイアグラムのすべてに機能があり、明らかに実際のシナリオにはオブジェクトの数が何倍もあり、これはカップリングとしてではなく「相互作用」ダイアグラムです。間に抽象化があります):
...これには、システムのみに機能があります(青色のコンポーネントは単なるデータであり、現在は結合図です)。
そして、これらのすべてについて浮上している考えがあり、SOLIDとより互換性のあるより準拠したOOPコンテキストでこれらの利点のいくつかを組み立てる方法がありますが、デザインと言葉はまだ見つかっていません。私はOOPに直接関連するすべての用語を使い回すのに慣れていたので、難しい。私はここで人々の答えを読んでそれを理解しようとし続け、また自分自身を策定するために最善を尽くしていますが、ECSの性質について非常に興味深いことがあります。それを使用しないアーキテクチャにもより広く適用できるかもしれません。また、この回答がECSプロモーションとして実現しないことを願っています!ECSの設計が私の考えを大きく変えたので、私はそれが非常に面白いと感じています