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


154

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

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

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

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

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


プラグインアーキテクチャが一般的なテーマとなっている理由を教えてください。それはどのような問題を解決しますか、それとも目標に取り組みますか?多くの拡張可能なシステム/アプリケーションは、なんらかの形式のプラグインを使用しますが、その形式は、解決される問題によってかなり異なります。
mdma

@mdma-それは素晴らしい質問です。拡張可能なシステムにはいくつかの共通の目標があると思います。おそらく、目標は一般的なものすべてであり、最適なソリューションは、システムの拡張性、システムで記述されている言語などによって異なります。しかし、IOCのようなパターンが多くの言語に適用されているのがわかり、同様のプラグイン(同じ機能の要求に対応するドロップイン用)を何度も実行するように求められました。さまざまなタイプのプラグインのベストプラクティスの概要を理解することは良いことだと思います。
justkt

回答:


89

これは、潜在的に有用な備考/例ほどの答えではありません。

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

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

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

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

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

1
スクリプト言語のポイントを拡張して、pythonやperlなどの既存の言語を組み込むことを検討する価値があることを示します
Rudi

真のルディ。多くの言語が埋め込まれるように設計されています。たとえば、Guileは埋め込みのためだけに作られています。アプリをスクリプト対応にする場合、これにより時間を節約できます。これらの言語のいずれかをドロップすることができます。
ヌファルイブラヒム2010

24

私の経験では、実際には2種類のプラグインアーキテクチャがあることがわかりました。

  1. 1つは、Eclipse model自由を可能にするためのものであり、自由に選択できるものに従います。
  2. narrow APIのプラグインは特定の機能を満たすため、通常、プラグインが従う必要があります。

別の方法でこれを述べるためには、プラグインがアプリケーションにアクセスすることを可能にする他の一方で、アクセスプラグインにアプリケーションを可能にします

区別は微妙で、特別な説明がない場合もあります。アプリケーションで両方を使用する必要があります。

私は、Eclipse / Opening up your App to pluginsモデルの豊富な経験はありません(Kalkieの投稿の記事は素晴らしいです)。私は日食が物事を行う方法について少し読んだが、それ以外は何もない。

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

これまでに行った作業のほとんどは、プラグインアーキテクチャを使用して、アプリがプラグインにアクセスできるようにしています。たとえば、時間/表示/地図データなどです。

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

  • 今、私はたいていDI frameworkその仕事のほとんどをしています。

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


@ジャスティンはい、DI =依存性注入。
導出

14

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

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


確かに良い例ですが、多くのアプリケーションが必要とするよりも大きくて複雑ですか?
justkt

はい、可能性があります。柔軟性の向上にはコストが伴います。しかし、それは別の視点を示していると思います。アプリケーションのメニューをプラグインまたはメインビューにできないのはなぜですか。
Patrick

6
Symfonyフレームワークの新しいバージョンでは、同じアプローチ(すべてがプラグインです)が使用されています。それらはバンドルと呼ばれますが、原理は同じです。それのアーキテクチャはかなりシンプルです。おそらくそれを見ておくべきでしょう:symfony-reloaded.org/quick-tour-part-4
Marijn Huizendveld

@Marjin Huizendveld-私が回答を賛成できるように、これを別の回答として追加する必要があります。興味深いフレームワークのように見えます!
justkt

11

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

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

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

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

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

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

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

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


7

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

興味があればもっと読んでください...


ありがとう、面白いですね。他の言語に同様のプリンシパルを適用するのはどれほど簡単ですか?
10

実際、MEFは.NETフレームワーク専用です。他のフレームワークについては何も知りません
BALKANGraph

7

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

スペックが次のような単語で満たされている場合:

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

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

プラグインを作成している顧客(または基本的なサポート担当者)のサポートは、アーキテクチャよりもはるかに難しい


5

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

ライブラリを管理するスクリプトに基づくアーキテクチャが最も効果的に機能するようです。スクリプト言語を使用すると、下位レベルのライブラリを高レベルで操作できるため、ライブラリは特定のインターフェイスから解放され、アプリケーションレベルのすべてのやり取りがスクリプトシステムのより柔軟な手に残ります。

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

プラグインをパッケージ化する方法は、個人の好みに大きく依存しますがPluginName.ext、ルートディレクトリなど、シンプルなインターフェースで圧縮アーカイブを使用しても問題はありません。


3

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

IOC(Inversion of Control)プリンシパル(read springframework)は、柔軟なベースを提供するためにうまく機能することを発見しました。これを特化して追加すると、プラグインの開発が簡単になります。

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

1

プラグインパターンは、クリーンなインターフェイスでクラスの動作を拡張するためのソフトウェアパターンです。多くの場合、クラスの動作はクラス継承によって拡張され、派生クラスはクラスの仮想メソッドの一部を上書きします。このソリューションの問題は、実装の非表示と競合することです。また、派生クラスが無関係な動作拡張の集合場所になる状況にもつながります。また、上記の「内部をスクリプト言語として作成し、その言語で最上位のものをすべて記述します。これにより、変更が容易になり、実質的に将来の証拠になります」のように、スクリプトを使用してこのパターンを実装します。ライブラリはライブラリを管理するスクリプトを使用します。スクリプト言語では、低レベルのライブラリを高レベルで操作できます。(上記同様)

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.