web-dev-qa-db-ja.com

柔軟なプラグインアーキテクチャの作成方法

私の開発作業の繰り返しのテーマは、社内プラグインアーキテクチャの使用または作成です。構成ファイル(XML、.confなど)、継承フレームワーク、データベース情報、ライブラリなど、さまざまな方法でアプローチしているのを見てきました。私の経験では:

  • データベースは、特にデータと混ざって、構成情報を保存するのに最適な場所ではありません
  • 継承階層を使用してこれを試行するには、プラグインに関する知識がコーディングされている必要があります。つまり、プラグインアーキテクチャはそれほど動的ではありません。
  • 構成ファイルは単純な情報を提供するのには適していますが、より複雑な動作を処理することはできません
  • ライブラリはうまく機能しているように見えますが、一方向の依存関係を慎重に作成する必要があります。

一緒に仕事をしたさまざまなアーキテクチャから学びたいと思っているので、私もコミュニティに提案を求めています。 SOLIDプラグインアーキテクチャをどのように実装しましたか?最悪の障害(またはこれまでに見た最悪の障害)は?新しいプラグインを実装する場合はどうしますか?アーキテクチャの面では、どのSDKまたはオープンソースプロジェクトで作業したのが、優れたアーキテクチャの最良の例ですか?

私が自分で見つけてきたいくつかの例:

これらの例は、さまざまな言語の長所を果たしているようです。優れたプラグインアーキテクチャは、必ずしも言語に関連付けられていますか?ツールを使用してプラグインアーキテクチャを作成するのが最善ですか、それとも自分の次のモデルでそれを行うのが最善ですか?

148
justkt

これは、答えではなく、潜在的に有用な発言/例の束ではありません。

  • アプリケーションを拡張可能にする効果的な方法の1つは、内部をスクリプト言語として公開し、その言語ですべてのトップレベルのものを記述することです。これにより、非常に変更可能になり、実質的に将来の証明になります(プリミティブが適切に選択され実装されている場合)。この種の成功例はEmacsです。機能を拡張したい場合、APIを学習したり、別のプラグインを作成/コンパイルする必要がないので、Eclipseスタイルのプラグインシステムよりもこれを好みます。現在のバッファー自体に3行のスニペットを記述し、評価して使用することができます。非常に滑らかな学習曲線と非常に楽しい結果。

  • 私が少し拡張したアプリケーションの1つは、 Trac です。コンポーネントアーキテクチャがあり、この状況では、タスクは拡張ポイントをアドバタイズするモジュールに委任されます。次に、これらのポイントに収まり、フローを変更する他のコンポーネントを実装できます。上記のKalkieの提案に少し似ています。

  • もう1つ良いのは、 py.test です。 「最高のAPIはAPIなし」という哲学に従っており、純粋にあらゆるレベルで呼び出されるフックに依存しています。規約に従って名前が付けられたファイル/関数でこれらのフックをオーバーライドし、動作を変更できます。サイト上のプラグインのリストを参照して、プラグインの実装の速さを確認してください。

いくつかの一般的なポイント。

  • 拡張不可能/ユーザーが変更できないコアをできるだけ小さくするようにしてください。可能な限りすべてを上位レイヤーに委任して、拡張性を高めます。悪い選択の場合よりもコアで修正するものが少なくなります。
  • 上記の点に関連するのは、最初からプロジェクトの方向について多くの決定をすべきではないということです。必要な最小のサブセットを実装してから、プラグインの作成を開始します。
  • スクリプト言語を埋め込む場合は、アプリケーションのおもちゃの言語justではなく、一般的なプログラムを記述できる完全な言語であることを確認してください。
  • できる限りボイラープレートを減らします。サブクラス化、複雑なAPI、プラグインの登録などは気にしないでください。 easyだけでなくpossible拡張します。これにより、プラグインAPIがさらに使用され、エンドユーザーがプラグインを作成するようになります。プラグイン開発者だけではありません。 py.testはこれをうまく行います。私の知る限り、Eclipseは しない です。
81
Noufal Ibrahim

私の経験では、実際には2種類のプラグインアーキテクチャがあります。

  1. Eclipse modelこれは、自由を可能にするためのものであり、無制限です。
  2. もう1つは、通常、narrow APIは、プラグインが特定の機能を満たすためです。

別の言い方をすれば、1つはプラグインによるアプリケーションへのアクセスを許可し、もう1つはアプリケーションによるアクセスを許可しますプラグイン

区別は微妙であり、場合によっては区別がありません...アプリケーションの両方に必要です。

私は、Eclipse /プラグインモデルへのアプリのオープンに関する豊富な経験はありません(Kalkieの投稿の記事は素晴らしいです)。 Eclipseの処理方法について少し読みましたが、それ以上のものはありません。

Yeggeの properties blog では、プロパティパターンを使用してプラグインと拡張性を実現する方法について少し説明しています。

私が行ったほとんどの作業では、プラグインアーキテクチャを使用して、アプリがプラグイン(時間/表示/マップデータなど)にアクセスできるようにしました。

何年も前に、私はすべてを管理するためにファクトリー、プラグインマネージャー、設定ファイルを作成し、実行時に使用するプラグインを決定しました。

  • 今、私は通常DI frameworkその作業の大部分を行います。

サードパーティのライブラリを使用するためにアダプタを記述する必要がありますが、通常はそれほど悪くはありません。

24
derivation

私が見た中で最高のプラグインアーキテクチャの1つは、Eclipseに実装されています。プラグインモデルを備えたアプリケーションではなく、すべてがプラグインです。基本アプリケーション自体はプラグインフレームワークです。

http://www.Eclipse.org/articles/Article-Plug-in-architecture/plugin_architecture.html

14
Patrick

私はかつて、各顧客がシステムをセットアップできるように非常に柔軟でなければならないプロジェクトに取り組みましたが、私たちが見つけた唯一の良い設計は顧客にC#コンパイラを出荷することでした!

仕様が次のような単語で満たされている場合:

  • フレキシブル
  • プラグイン
  • カスタマイズ可能

私の経験のように、システムをどのようにサポートするか(および各顧客が通常のケースであり、プラグインを必要としないと考えるため、どのようにサポートに課金されるか)について多くの質問をします。

プラグインを作成する顧客(または専用のサポート担当者)のサポートは、アーキテクチャよりもはるかに困難です。

8
Ian Ringrose

過去に使用したかなり単純な手法について説明します。このアプローチでは、C#リフレクションを使用して、プラグインの読み込みプロセスを支援します。この手法は変更できるため、C++に適用できますが、リフレクションを使用できるという利便性が失われます。

IPluginインターフェイスは、プラグインを実装するクラスを識別するために使用されます。アプリケーションがプラグインと通信できるようにするためのメソッドがインターフェースに追加されます。たとえば、アプリケーションがプラグインに初期化を指示するために使用するInitメソッド。

プラグインを見つけるために、アプリケーションは.Netアセンブリのプラグインフォルダーをスキャンします。各アセンブリがロードされます。リフレクションは、IPluginを実装するクラスのスキャンに使用されます。各プラグインクラスのインスタンスが作成されます。

(または、Xmlファイルにロードするアセンブリとクラスがリストされている場合があります。これによりパフォーマンスが向上する場合がありますが、パフォーマンスの問題は見つかりませんでした)。

Initメソッドは、各プラグインオブジェクトに対して呼び出されます。アプリケーションインターフェイスを実装するオブジェクトへの参照が渡されます:IApplication(またはアプリに固有の名前、たとえばITextEditorApplication)。

IApplicationには、プラグインがアプリケーションと通信できるようにするメソッドが含まれています。たとえば、テキストエディタを記述している場合、このインターフェイスには、プラグインが現在開いているドキュメントのコレクションを列挙できるようにするOpenDocumentsプロパティがあります。

このプラグインシステムは、LuaPlugin関数とアプリケーションインターフェイスをLuaスクリプトに転送するIPluginなどの派生プラグインクラスを作成することにより、Luaなどのスクリプト言語に拡張できます。

この手法により、開発中にIPluginIApplicationおよびその他のアプリケーション固有のインターフェイスを繰り返し実装できます。アプリケーションが完成し、適切にリファクタリングされたら、公開されたインターフェイスを文書化できます。ユーザーが独自のプラグインを作成できるNiceシステムが必要です。

7
Ashley Davis

通常、MEFを使用します。 Managed Extensibility Framework(または略してMEF)は、拡張可能なアプリケーションの作成を簡素化します。 MEFは、アプリケーション拡張機能をロードするために活用できる検出および構成機能を提供します。

興味のある方は more ... を読んでください

7
BALKANGraph

私の経験では、柔軟なプラグインアーキテクチャを作成する2つの最良の方法は、スクリプト言語とライブラリです。私の考えでは、これらの2つの概念は直交しています。この2つは、関数型プログラミングやオブジェクト指向プログラミングのように、任意の割合で混在させることができますが、バランスを取ると最大の強みが得られます。通常、ライブラリは、動的機能を使用して特定のinterfaceを実現しますが、スクリプトは、動的インターフェイスを使用してfunctionalityを強調する傾向があります。

スクリプト管理ライブラリに基づいたアーキテクチャが最適に動作するようだとわかりました。スクリプト言語を使用すると、低レベルのライブラリを高レベルで操作できるため、ライブラリは特定のインターフェイスから解放され、アプリケーションレベルの対話はすべて、より柔軟なスクリプトシステムに委ねられます。

これが機能するには、スクリプトシステムに、アプリケーションデータ、ロジック、GUIへのフック、およびライブラリからのコードのインポートと実行の基本機能を備えた、かなり堅牢なAPIが必要です。さらに、スクリプトは通常、アプリケーションが適切に記述されていないスクリプトから正常に回復できるという意味で、safeである必要があります。スクリプトシステムを間接層として使用することは、Something Bad™の場合にアプリケーションがより簡単にデタッチできることを意味します。

プラグインをパッケージ化する方法は、個人の好みに大きく依存しますが、シンプルなインターフェースを備えた圧縮アーカイブ、例えばPluginName.extルートディレクトリ。

3
Jon Purdy

「どのコンポーネントがプラグインになると予想されますか?」という質問に最初に答える必要があると思います。この数を絶対最小値または爆発をテストする必要がある組み合わせの数に維持する必要があります。プラグイン機能からコア製品(柔軟性が高すぎてはならない)を分離するようにしてください。

IOC(Inversion of Control)プリンシパル(read springframework)プリンシパルは柔軟なベースを提供するのにうまく機能することがわかりました。

  • 「プラグインタイプアドバタイズメントとしてのインターフェイス」メカニズムのコンテナをスキャンできます。
  • コンテナを使用して、プラグインが必要とする可能性のある一般的な依存関係(ResourceLoaderAwareまたはMessageSourceAware)を注入できます。
3
Justin