Plugin based app: Extensibility & Flexiblity

Arokh

Centurion
Joined
Apr 11, 2006
Messages
124
In the course of coding a plugin based application (which is progressing very well),
I sometimes worry about the aspects of Extensibility & Flexiblity.

Plugins may communicate with other plugins so it obviously relies heavily on interfaces.

My current (project)structure is like this:
Executable
  • Central point for loading & storing modules
  • Provides methods so modules can load other instanciated modules
  • Implements an interface which exposes those methods (Located in main library)


Main library
  • Has to be referenced by every module
  • Common tools (classes, methods, etc)
  • Contains IMod interface (base requirement for a module)
  • Contains interfaces of (standart)modules which come with the application


Module
  • Has to implement IMod interface
  • May get other module instances


So basically when the application starts, it creates an instance of every class that implements the IMod interface.
Then it calls the method Initialize (IMod method), passing it the instance of the executable.


Now to the actual problem:
If I were to change/add/remove something from the main library,
wouldn't that break every module which uses the old version of that library?
 
You could create an additional library that holds just the interfaces, all the other parts (UI, main library etc.) reference this library but all other work is done at runtime - this way there is no hard coded dependencies apart from the interfaces.
 
Yeh, you obviously should seperate the interfaces into a seperate dll.

Also, the way you are designing the plug-in system is the same way it's designed on all the plug-in examples online (codeproject, sourceforge, etc), which isn't very extensible.

What is your central repository of modules? A database, xml file? Why not have the plug-in system parse a certain directory and look for dll's that contain classes that implement the module interfaces? This would be much more flexible.

Having a single interface that every plug-in must implement is not extensible. How is that extensible? How many different kinds of plug-ins are you going to have, how are they going to communicate with data, with the UI? Instead, use attributes to define an interface as a plug-in interface and another attribute to define a class as a connector to that interface.

[Slot("VideoPlugin")]
public interface IVideoPlugin

[Connector("VideoPlugin")]
public sealed class VlcPlugin


And what are you talking about, you instantiate an object of every plug-in module at start-up?? How is that flexible? Flexible would mean the plug-in is instantiated when it is used. Also, the ability to remove and add plug-ins at run-time is extensible. Reflection.


Don't underestimate the complexity of a plug-in system. Ecliple is an example of a well-architected plug-in system. The OSGI is a specification for a plug-in system.
 
woah Diesel, slow down.

This is a one man project and my first time trying to make an application which is completely based on modules.
So I know there I limits to what I can achieve in a short period of time.

Either way, I'm still interested in your criticism:
Also, the way you are designing the plug-in system is the same way it's designed on all the plug-in examples online (codeproject, sourceforge, etc), which isn't very extensible.

What is your central repository of modules? A database, xml file? Why not have the plug-in system parse a certain directory and look for dll's that contain classes that implement the module interfaces? This would be much more flexible.
Thats the way I'm currently doing it, at least the gist of it:
The plugin writer compiles a dll which implements the IMod interface (Main Lib),
the (my) program then looks in dll files (placed the plugin dir) for that interface.

If it find the implemented interface it creates an instance of it.
(Of course there will be some controls like disabling, loading etc for modules)
But the instancing phase is not the one where the plugin actually start,
it should just do its "preparations" (at least I want to design it that way).

The actual part where everything should start is when I call the plugins initialization method (a method in IMod interface).

Having a single interface that every plug-in must implement is not extensible. How is that extensible?
I don't quiet understand.
In what way am I hindering the writer to extend the plugin beyond that interface?
Since he/she can still implement, inherit other classes.
The interface only allows me, the plugin writer, to easily communicate with other modules currently loaded in the application.

How many different kinds of plug-ins are you going to have, how are they going to communicate with data, with the UI?
Well, how that is done, is up to the plugin.
(If there is no module loaded the application would do nothing, everything is module based even the GUI,
of course I'm writing those modules too)


Instead, use attributes to define an interface as a plug-in interface and another attribute to define a class as a connector to that interface.
That is a nice idea which I will take into consideration,
maybe when I redesign it again I will use that approach.
I've been using instanceof() to see if the plugin has implemented another interface (besides IMod) which is able to "manipulate" the GUI.

And what are you talking about, you instantiate an object of every plug-in module at start-up?? How is that flexible? Flexible would mean the plug-in is instantiated when it is used. Also, the ability to remove and add plug-ins at run-time is extensible. Reflection.
As I before in this post of course there will be controls to disable, enable plugins.
I just wanted to point out the two phases I want the plugin to go through when it starts.
Preparations - Instantiation
Starting - Initialization (IMod method)

Don't underestimate the complexity of a plug-in system. Ecliple is an example of a well-architected plug-in system. The OSGI is a specification for a plug-in system.
I never did, as I said I'm an one man army (of rekruts :D ) and I know that I can't make it perfect the first time around.


I guess the first thing I will be doing it like you & PlausiblyDamp said,
creating a library where only the needed interfaces are in it.
 
I mispelled Eclipse, Ecliple is catchy though.

Is this for work or for a personal project?


How many different kinds of plug-ins are you going to have, how are they going to communicate with data, with the UI?
Well, how that is done, is up to the plugin.
(If there is no module loaded the application would do nothing, everything is module based even the GUI,
of course I'm writing those modules too)

The plug-ins can't define how they show up in the UI. The plug-in framework must define that. If you only have an IMod interface that the plug-ins must implement, there are going to be a lot of GUI specific methods and they are going to be really general.

To re-tread on that thought, a plug-in shouldn't know or care what system it is being plugged into. It could be plugged into a web app, desktop app, silverlight app, whatever, therefore it doesn't know how to manipulate the UI, so the methods to 'view' the plug-in must be in the (a) interface that the plug-in implements.

You should just continue with what you have now though all the way through. That way you can see the major problems that come up during integration with the UI and other modules.
 
Well it is no commercial project,
it is rather a personal one, but I would like to think that other people will use it too.
(Since there are currently only discontinued or "not so good" alternatives, my chances aren't even that bad. :rolleyes: )

Is it really a bad idea to write the framework that way it doesn't involve with any specific application logic?
Then writing the base modules which defines what the program has to do.
(GUI, backend logic etc)
And then giving the user the API (interfaces) to those basic modules.

But I guess you are right. I'll just continue to write it and I'll see where I end up :) .

... but I guess not today, my (wannabe) server just gave up on me.
Hopefully nothing bad.
 
You may find having a couple of interfaces can clean up some complexity without involving too much work for a starting project. Keep the IMod interface as it is for core plugin functionality (Initialiasation, cleanup, enable / disable etc), with different iterfaces for plugins that extend menus / toolbars, dialogs etc.

This can give a cleaner seperation of functionality while allowing more complex plugins to implements as many interfaces as they need.

You may find some usefule reading at the following places
http://www.icsharpcode.net/OpenSource/SD/Default.aspx - the book they published is a free pdf now, has a lot of conceptual and code based work on a very comprehensive plugin system.

http://www.codeplex.com/MEF
http://msdn.microsoft.com/en-us/library/ms972962.aspx
http://msdn.microsoft.com/en-us/library/system.addin.contract.aspx
 
Wow, I didn't expect to pop in here for a look after so much time away and find a discussion so relevant to what I am currently working on underway.

Any plugin that supplies GUI material should have it's GUI elements put on a control within the plugin. A method should be provided in the Interface that gets an instance of this control, which the main app can then add where it see's fit. An example of this that I wrote a while back is either in the Code Library, or Tutorials section. Can't remember which of the top of my head.

EDIT: Here it is http://www.xtremedotnettalk.com/showthread.php?t=70920&highlight=plugin

Also, when scanning the plugins directory for valid plugins, you should do that in a separate AppDomain. The problem is that if you do it in your main AppDomain it keeps a copy of ALL assemblies loaded even after you supposedly release them; whether they are a valid plugin or not. Using a separate AppDomain allows you to release these references and the memory associated with them once the secondary AppDomain is closed.

You can verify that this is happening currently by adding the return string from the following function to a MessageBox after you scan for plugins in the plugin directory. You should throw a couple of assemblies that aren't valid plugins to test. If you see them in the list of loaded assemblies after the scan is completed, it is due to the problem I mention.

[vbnet] Public Function ShowAssemblies() As String

Dim sb As New System.Text.StringBuilder

For Each LoadedAssembly As Assembly In AppDomain.CurrentDomain.GetAssemblies()
sb.Append(LoadedAssembly.GetName().Name)
sb.Append(vbCrLf)
Next

Return sb.ToString.TrimEnd(vbCrLf, " ", vbTab)
End Function[/vbnet]

Incidentally, I am currently working on (after quite a long sabatical from the project) a User Control that you can drop in any project that instantly makes it plugin enabled. In the design time interface you can add the plugin directory, and assembies that carry your plugin interfaces. At runtime it checks the directory for the appropriate interfaces in assemblies within the plugin directory and allows you to load them at will, and provides the access to their methods, properties, etc.

It just seemed a lot easier to do this work once in a generic enough way that it could be used without modification from project to project.
 
Last edited:
MEF sounds like it is pretty powerful and would do the job. However it is also quite complex and not very intuitive. In addition, for most simple apps that just want to accept some plugins it is like using a sledgehammer to crack a nut.

A person that has written a plugin based app before using the methods discussed above, would have to learn an entirely new way of doing things just to get off the ground. Sometimes a steep learning curve can actually hinder a project rather than pushing it forward, especially if the powerful advantages that create the learning curve aren't needed.
 
Back
Top