views:

669

answers:

8

A repeating theme in my development work has been the use of or creation of an in-house plug-in architecture. I've seen it approached many ways - configuration files (XML, .conf, and so on), inheritance frameworks, database information, libraries, and others. In my experience:

  • A database isn't a great place to store your configuration information, especially co-mingled with data
  • Attempting this with an inheritance hierarchy requires knowledge about the plug-ins to be coded in, meaning the plug-in architecture isn't all that dynamic
  • Configuration files work well for providing simple information, but can't handle more complex behaviors
  • Libraries seem to work well, but the one-way dependencies have to be carefully created.

As I seek to learn from the various architectures I've worked with, I'm also looking to the community for suggestions. How have you implemented a solid plug-in architecture? What was your worst failure (or the worst failure you've seen)? What would you do if you were going to implement a new plug-in architecture? What SDK or open source project that you've worked with has the best example of a good architecture?

A few examples I've been finding on my own:

These examples seem to play to various language strengths. Is a good plugin architecture necessarily tied to the language? Is it best to use tools to create a plugin architecture, or to do it on one's own following models?

+3  A: 

Usualy I use MEF. The Managed Extensibility Framework (or MEF for short) simplifies the creation of extensible applications. MEF offers discovery and composition capabilities that you can leverage to load application extensions.

If you are interested read more...

Muse VSExtensions
Thanks, looks interesting. How easy is it to apply similar principals across other languages?
justkt
Actually MEF is only for .NET framework I dont know anything about other frameworks
Muse VSExtensions
+3  A: 

One of the best plug-in architectures that I have seen is implemented in Eclipse. Instead of having an application with a plug-in model, everything is a plug-in. The base application itself is the plug-in framework.

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

kalkie
Certainly a good example, but is it bigger and more complex than many applications require?
justkt
Yes it could be, the increase in flexibility comes with a cost. But I think it shows a different view point. Why couldn't the menu of you application be a plug-in or the main view?
kalkie
Thanks for the helpful link.
justkt
The same approach (everything is a plugin) is used in the new version of the Symfony framework. They are called bundles but the principle is the same. It's architecture is fairly simple, perhaps you should have a look at it: http://symfony-reloaded.org/quick-tour-part-4
Marijn Huizendveld
@Marjin Huizendveld - you should add this as a separate answer so I can upvote the answer. Looks like an interesting framework!
justkt
+7  A: 

This is not an answer as much as a bunch of potentially useful remarks/examples.

  • One effective way to make your application extensible is to expose it's internals as a scripting language and write all the top level stuff in that language. This makes is quite modifiable and practically future proof (if your primitives are well chosen and implemented). A success story of this kind of thing is Emacs. I prefer this to the eclipse style plugin system because if I want to extend functionality, I don't have to learn the API and write/compile a separate plugin. I can write a 3 line snippet in the current buffer itself, evaluate it and use it. Very smooth learning curve and very pleasing results.

  • One application which I've extended a little is Trac. It has a component architecture which in this situation means that tasks are delegated to modules that advertise extension points. You can then implement other components which would fit into these points and change the flow. It's a little like Kalkie's suggestion above.

  • Another one that's good is py.test. It follows the "best API is no API" philosophy and relies purely on hooks being called at every level. You can override these hooks in files/functions named according to a convention and alter the behaviour. You can see the list of plugins on the site to see how quickly/easily they can be implemented.

A few general points.

  • Try to keep your non-extensible/non-user-modifiable core as small as possible. Delegate everything you can to a higher layer so that the extensibility increases. Less stuff to correct in the core then in case of bad choices.
  • Related to the above point is that you shouldn't make too many decisions about the direction of your project at the outset. Implement the smallest needed subset and then start writing plugins.
  • If you are embedding a scripting language, make sure it's a full one in which you can write general programs and not a toy language just for your appl.
  • Reduce boilerplate as much as you can. Don't bother with subclassing, complex APIs, plugin registration and stuff like that. Try to keep it simple so that it's easy and not just possible to extend. This will let your plugin API be used more and will encourage end users to write plugins. Not just plugin developers. py.test does this well. Eclipse as far as I know, does not.
Noufal Ibrahim
Great suggestions, thank you.
justkt
You're welcome.
Noufal Ibrahim
I would extend the scripting language point to that it is worth considering to embed an existing language like python or perl
Rudi
True Rudi. Many languages are being made these designed to be embedded. Guile for example, is made just for embedding. This saves time if you're making your app scriptable. You can just drop in one of these languages.
Noufal Ibrahim
+3  A: 

In my experience I've found there are really two types of plug-in Architectures. One follows the Eclipse model which is meant to allow for freedom and is open-ended. The other usually requires plugins to follow a narrow API because the plugin will fill a specific function. To state this in a different way, one allows plugins to access your application while the other allows your application to access plugins. The distinction is subtle, and sometimes there is no distiction... you want both for your application.

I do not have a ton of experience with Eclipse/Opening up your App to plugins model (the article in Kalkie's post is great). I've read a bit on the way eclipse does things, but nothing more than that. Yegge's properties blog talks a bit about how the use of the properties pattern allows for plugins and extensibility.

Most of the work I've done has used a plugin architecture to allow my app to access plugins, things like time/display/map data, etc. Years ago I would create factories, plugin managers and config files to manage all of it and let me determine which plugin to use at runtime. Now I usually just have a DI framework do most of that work. I still have to write adapters to use third party libraries, but they usually aren't that bad.

derivation
Awesome article linked.
justkt
DI = (dependency injection)?
Justin
@Justin yes, DI = dependency injection.
derivation
+2  A: 

I once worked on a project that had to be so flexible in the way each customer could setup the system, which the only good design we found was to ship the customer a C# compiler!

If the spec is filled with words like:

  • Flexible
  • Plug-In
  • Customisable

Ask lots of questions about how you will support the system (and how support will be charged for, as each customer will think their case is the normal case and should not need any plug-ins.), as in my experience

The support of customers (or fount-line support people) writing Plug-Ins is a lot harder than the Architecture

Ian Ringrose
+2  A: 

I think you need to first answer the question: "What components are expected to be plugins?" You want to keep this number to an absolute minimum or the number of combinations which you must test explodes. Try to separate your core product (which should not have too much flexibility) from plugin functionality.

I've found that the IOC (Inversion of Control) principal (read springframework) works well for providing a flexible base, which you can add specialization to to make plugin development simpler.

  • You can scan the container for the "interface as a plugin type advertisement" mechanism.
  • You can use the container to inject common dependencies which plugins may require (i.e. ResourceLoaderAware or MessageSourceAware).
Justin
A: 
Jon Purdy
A: 

I'll describe a fairly simple technique that I have use in the past. This approach uses C# reflection to help in the plugin loading process. This technique can be modified so it is applicable to C++ but you lose the convenience of being able to use reflection.

An IPlugin interface is used to identify classes that implement plugins. Methods are added to the interface to allow the application to communicate with the plugin. For example the Init method that the application will use to instruct the plugin to initialize.

To find plugins the application scans a plugin folder for .Net assemblies. Each assembly is loaded. Reflection is used to scan for classes that implement IPlugin. An instance of each plugin class is created.

(Alternatively, an Xml file might list the assemblies and classes to load. This might help performance but I never found an issue with performance).

The Init method is called for each plugin object. It is passed a reference to an object that implements the application interface: IApplication (or something else named specific to your app, eg ITextEditorApplication).

IApplication contains methods that allows the plugin to communicate with the application. For instance if you are writing a text editor this interface would have an OpenDocuments property that allows plugins to enumerate the collection of currently open documents.

This plugin system can be extended to scripting languages, eg Lua, by creating a derived plugin class, eg LuaPlugin that forwards IPlugin functions and the application interface to a Lua script.

This technique allows you to iteratively implement your IPlugin, IApplication and other application-specific interfaces during development. When the application is complete and nicely refactored you can document your exposed interfaces and you should have a nice system for which users can write their own plugins.

Ashley Davis