私からは少し物議を醸す意見がありますが、少なくとも現在一般的に適用されている種類のOOPが、私の特定のドメインで最大規模のソフトウェアを作成するのに役立つとは思いません(VFX、シーンの編成とアプリケーションで多少似ています)ゲームとしての状態)。中小規模で非常に便利だと思います。過去にモブを招待したことがあるので、ここでは少し注意する必要がありますが、これは私の特定のタイプのドメインでの狭い経験にあると見なす必要があります。
私がよく目にする難しさは、データをカプセル化するこれらの小さな具体的なオブジェクトがすべてある場合、それらはすべて互いに話し合いたいということです。それらの間の相互作用は、次のように非常に複雑になる可能性があります(数千のオブジェクトにまたがる実際のアプリケーションでは、はるかに複雑になる場合を除きます)。

そして、これは「相互作用グラフ」ほど結合に直接関係する依存関係グラフではありません。これらの具体的なオブジェクトを互いに分離するための抽象化が存在する可能性があります。直接Foo
話さないかもしれません。代わりに、この種の何かBar
を通してそれと話すかもしれません。IBar
このグラフは、分離されていても、相互に通信しているため、接続Foo
されたままになります。Bar
そして、独自の小さなエコシステムを構成する中小規模のオブジェクト間のこのすべての通信は、私のドメイン内の大規模なコードベースの全体規模に適用された場合、維持するのが非常に困難になる可能性があります。また、副作用などに関して、オブジェクト間のこれらすべての相互作用で何が起こるかを推論するのが難しいため、保守が非常に困難になります。
代わりに、私が有用だと思ったのは、コードベース全体を、中央の「データベース」にアクセスする完全に独立した大量のサブシステムに編成することです。次に、各サブシステムはデータを入力および出力します。他のいくつかのサブシステムは同じデータにアクセスする可能性がありますが、1つのシステムが互いに直接通信することはありません。

...またはこれ:

...そして個々のシステムはもはや状態をカプセル化しようとはしません。独自のエコシステムになろうとはしていません。代わりに、中央データベースのデータの読み取りと書き込みを行います。
もちろん、各サブシステムの実装では、それらの実装を支援するためにいくつかのオブジェクトを使用する場合があります。そしてそれが、これらのサブシステムの実装においてOOPが非常に役立つと私が思うところです。しかし、これらのサブシステムはそれぞれ、比較的中規模から小規模のプロジェクトを構成しており、大きすぎないため、OOPが非常に役立つのはその中規模から小規模です。
最小限の知識を持つ「組立ラインプログラミング」
これにより、各サブシステムは、外の世界で何が起こっているのかをほとんど知らなくても、自分のことを行うことに集中できます。物理学に焦点を当てている開発者は、物理学サブシステムに腰を下ろし、ソフトウェアがどのように機能するかについてほとんど知りません。ただし、モーションコンポーネント(データのみ)などを取得し、そのデータに物理学を適用して変換できる中央データベースがあります。そして、それは彼の仕事を非常に単純にし、他のすべてがどのように機能するかについての最小限の知識で彼が最善を尽くすことができるようにします。中央データの入力と中央データの出力:他のすべてが機能するためには、各サブシステムが正しく実行する必要があるのはこれだけです。これは、私の分野で「組立ラインプログラミング」に最も近いものです。
各サブシステムの焦点が狭いため、テストも非常に簡単です。特定のシステムに関連する最小限のデータを生成し、特定のシステムが特定の入力に対して正しい出力を提供するかどうかをテストするほど、依存性注入を使用して具体的なオブジェクトをモックすることはなくなりました。テストするシステムが非常に少ないため(複雑なソフトウェアを構成できるのはわずか数十)、必要なテストの数も大幅に削減されます。
カプセル化を破る
次に、システムは、互いの存在を事実上認識しない独立したサブシステムを介して、中央のアプリケーション状態を変換するかなりフラットなパイプラインに変わります。別のシステムが処理するデータベースに中央イベントをプッシュする場合もありますが、その別のシステムは、そのイベントがどこから発生したかを認識していません。これが、少なくとも私のドメインで複雑さに取り組むための鍵であり、エンティティコンポーネントシステムを介して効果的に行われていることがわかりました。
それでも、これを達成し、システムがそれぞれと通信する必要を回避するためにカプセル化を破っているので、これらすべてのサブシステムを分離し、外界の最小限の知識でそれらを動作させるために、大規模な手続き型または関数型プログラミングに近いものに似ています他の。ズームインすると、これらのサブシステムのいずれかを実装するために使用されているオブジェクトのシェアが見つかる場合がありますが、最も広いスケールでは、システムはOOP以外のものに似ています。
グローバルデータ
私は、最初はECSを自分のドメインのアーキテクチャ設計に適用することに非常に躊躇していたことを認めなければなりません。 、グローバルにアクセス可能なデータの集まりのように見えます。
しかし、これは大きな問題ではないことがわかりました。不変条件を非常に効果的に維持でき、おそらく以前よりもさらに良くなります。その理由は、ECSがすべてをシステムとコンポーネントに編成する方法によるものです。たとえば、最もハッキーな状況下でも、オーディオシステムがモーションコンポーネントを変更しようとしないので安心できます。調整が不十分なチームであっても、ECSが劣化して、どのシステムがどのコンポーネントにアクセスするかを判断できなくなる可能性はほとんどありません。これは、紙面ではかなり明白であり、特定のシステムがアクセスする理由は事実上まったくないためです。不適切なコンポーネント。
それどころか、以前のコードベースで緩い調整とクランチタイムの下で行われたハッキーなことの多くは、X線抽象化を急いで試みて行われたため、データを広く開いた状態でハッキーなことに対する以前の誘惑の多くを取り除くことがよくありました。オブジェクトのエコシステムの内部にアクセスします。人々が急いで、アクセスしたいデータを取得して処理しようとした結果、抽象化が漏れ始めました。彼らは基本的に、データにアクセスしようとしてフープを飛び越えていたため、インターフェイスデザインが急速に劣化していました。
特定のタイプのコンポーネントを変更するシステムは1つしかないことが多いため(一部の例外的なケースでは2つ)、システムの編成方法が原因で、カプセル化に漠然と似ているものがあります。しかし、彼らはそのデータを所有しておらず、そのデータを取得するための関数を提供していません。システムは相互に通信しません。これらはすべて、中央のECSデータベース(これらすべてのシステムに注入する必要がある唯一の依存関係)を介して動作します。
柔軟性と拡張性
これは、エンティティコンポーネントシステムに関する外部リソースですでに広く議論されていますが、哺乳類、昆虫、植物である生き物の提案のような概念を破るようなものでさえ、後知恵で根本的に新しい設計アイデアに適応するのに非常に柔軟です。もやしは一気に日光の下で去ります。
その理由の1つは、壊す中心的な抽象化がないためです。このためのより多くのデータが必要な場合、または植物、哺乳類、昆虫に必要なコンポーネントをつなぎ合わせるエンティティを作成するだけの場合は、いくつかの新しいコンポーネントを導入します。昆虫、哺乳類、植物のコンポーネントを処理するように設計されたシステムは、自動的にそれを取得し、コンポーネントの新しい組み合わせでエンティティをインスタンス化するコード行を追加する以外に、何も変更せずに必要な動作を得ることができます。まったく新しい機能が必要な場合は、新しいシステムを追加するか、既存のシステムを変更するだけです。
他の場所であまり議論されていないのは、これにより、予期していなかったコンセプトを破る設計変更がないシナリオでも、メンテナンスがどれだけ簡単になるかということです。ECSの柔軟性を無視しても、コードベースが特定の規模に達したときに、物事を本当に単純化することができます。
オブジェクトをデータに変換する
上記の最初のグラフに近いコードベースを維持するのが難しいことを私が見た以前のOOPを多用するコードベースではCar
、この図の類推のために必要なコードの量が爆発的に増加しました。

...複数のインターフェイスを実装する完全に別個のサブタイプ(クラス)として構築する必要がありました。そのため、システムには爆発的な数のオブジェクトがありました。指向性ライトからのポイントライト用の個別のオブジェクト、別のライトからの魚眼カメラ用の個別のオブジェクトなどです。数十の抽象的なインターフェイスを無限の組み合わせで実装する数千のオブジェクトがありました。
それをECSと比較すると、必要なのは数百であり、コードのごく一部を使用する前にまったく同じことを行うことができました。これにより、類推的なCar
エンティティがクラスを必要としないものに変わったためです。これは、1つのタイプの一般化されたインスタンスとしてのコンポーネントデータの単純なコレクションになりますEntity
。
OOPの代替案
そのため、このような場合、設計の最も広いレベルでOOPを過剰に適用すると、保守性が大幅に低下し始める可能性があります。システムの最も広い鳥瞰図では、システムを平坦化するのに役立ち、オブジェクトと相互作用するオブジェクトと相互作用するオブジェクトを抽象的にモデル化しようとしないでください。
私が過去と現在で取り組んだ2つのシステムを比較すると、新しいシステムにはより多くの機能がありますが、数十万のLOCが必要です。前者は2000万以上のLOCを必要としました。もちろん、前者には大きなレガシーがあったため、これは最も公平な比較ではありませんが、レガシーの手荷物なしで機能的に非常に等しい2つのシステムのスライスを取得すると(少なくとも私たちが得ることができるのとほぼ同じくらい)、 ECSは、コードのごく一部で同じことを実行します。これは、システム内に存在するクラスの数を、それらを処理するための大量のシステムを備えた生データ(コンポーネント)のコレクション(エンティティ)に変換することで劇的に削減するためです。中小物の船積みの。
真に非OOPのパラダイムが実際に大規模なソリューションにとってより良い選択であるシナリオはありますか?それとも、最近では前代未聞ですか?
前代未聞とは程遠いです。たとえば、上記で説明したシステムは、ゲームで広く使用されています。私の分野では非常にまれです(私の分野のアーキテクチャのほとんどは純粋なインターフェイスを備えたCOMのようなものであり、これは私が過去に取り組んだタイプのアーキテクチャです)が、ゲーマーが何をしているのかをじっと見つめていることがわかりましたアーキテクチャを設計することで、それが成長し、成長しても非常に理解しやすいものを作成できるという点で、世界に違いが生まれました。
そうは言っても、ECSはそれ自体がオブジェクト指向プログラミングの一種であると考える人もいます。もしそうなら、データ(コンポーネントとそれらを構成するエンティティ)と機能(システム)が分離されているため、ほとんどの人が考えるようなOOPとは似ていません。これには、OOPの最も基本的な側面の1つと見なされることが多い、広範なシステムレベルでのカプセル化を放棄する必要があります。
高水準コーディング
しかし、通常、より高いレベルのソリューションの断片は、ほとんどの場合、OOP方式でまとめられているように思われます。
アプリケーションを非常に高レベルのコードと組み合わせることができる場合、チームが維持する必要のあるコードに関しては、規模がかなり小さいか中程度になる傾向があり、おそらくOOPを使用して非常に効果的にアセンブルできます。
VFXの私の分野では、レイトレーシング、画像処理、メッシュ処理、流体力学などの比較的低レベルの処理を行う必要があり、実際に競合しているため、これらをサードパーティ製品から単純に組み合わせることができません。低レベルで何ができるかという点でより多くの点で(ユーザーは、たとえば、より優れたGUIよりも、最先端の競争力のあるプロダクションレンダリングの改善に興奮します)。したがって、ビットとバイトの非常に低レベルのシャッフルから、スクリプト作成者が埋め込みスクリプト言語を介して作成する非常に高レベルのコードまで、さまざまなコードが存在する可能性があります。
コミュニケーションのインターウェブ
しかし、高レベル、低レベル、またはコンボを問わず、あらゆるタイプのアプリケーションで十分な規模のポイントがあります。これは、すべてをカプセル化することはもはや役に立たないことがわかった、非常に複雑な中央アプリケーションの状態を中心に展開します。オブジェクトに。そうすることで、複雑さが増し、すべての間で行われる相互作用の量が増えるため、何が起こっているのかを推論するのが困難になる傾向があります。互いに話し合う必要のあるカプセル化された生態系としてそれぞれをモデル化するのをやめるほどの大規模なブレークポイントがなければ、何千もの生態系が互いに話し合うことについて推論するのはもはや簡単ではありません。それぞれが個別に単純であっても、全体として取り入れられたすべてのものは、心を圧倒する以上のものになり始める可能性があります。また、大規模システム全体の設計をOOPの原則のみに基づいて展開しようとすると、変更を加えたり、新しい機能を追加したり、デバッグしたりするために、多くの場合、その多くを取り入れなければなりません。少なくとも一部のドメインでは、ある程度の規模でカプセル化を解除するのに役立ちます。
その時点で、たとえば、物理システムに独自のデータをカプセル化させることは必ずしもそれほど有用ではありません(そうでない場合、多くのことがそれと通信してそのデータを取得し、適切な入力データで初期化する必要があります)。私は、ECSを介したこの代替手段が非常に役立つことを発見しました。これは、類推的な物理システムとそのようなすべての巨大なシステムを、「中央データベーストランスフォーマー」または「何か新しいものを出力する中央データベースリーダー」に変え、お互いに気付かないようにするためです。次に、各システムは、通信の非常に複雑なグラフでノードを形成するオブジェクトというよりも、フラットパイプラインのプロセスに似たものになり始めます。