On the CWE-LUG mailing list, someone asked a question about creating a program that can be extended with plugins. I thought the answer was so useful that I wanted to save it and make it available to others.
On 2/17/07, Mark wrote:
I’m a young programmer (just finishing high school) who has done a fair amount of programming with PHP, MySQL, and other web technologies. … How does one go about designing a program so it can be extended later with plugins, apis, and modules?
Ed Howland, veteran programmer, replied:
Mark, if i understand you correctly, you are seeking how to design a general purpose program that can be extended by others. It would help us to know what your target environment is. Especially if it is a dynamic language like Perl, Ruby or Python.Or a compiled language like Java or C/C++. The difference lies in linking others source code with yours, interpreted languages are easier in this respect.
That said, the general techniques are well-established. For purposes of illustration, I’ll call the code you are wanting to write the host (application) and the external modules, the guest (module.) The basic idea is to use various callbacks into the guest module from the host application. But first the guest application must register itself with the host (see it is like a hotel checkin…) This registration process can take many forms and is usually dictated by the programming environment. Anyway, the host maintains a list of registered guests. Each time a new guest registers, he is appended to said list.
Next, the host will then use the handle that represents the main object of the guest, and call an initialize routine in the guest. That routine sets stuff and gets a handle to the host so it can call things in the framework API to open windows, etc.
So the basic steps are:
- Devise a registration process
- Maintain a list of registered guest modules
- When starting, loop over your registered guests and call their initialize routines
- When a guest’s initialize routine is called, it calls pre-defined host API calls to open windows, or other things.
- These might cause the framework (in the host) to callback to the guest to display the window, and paint the contents of the windows.
You want to make your plugin callback interface as narrow as possible. And you want your host API to be simple to create widgets, windows, whatever in a few easy steps. If using a O-O language like Java or C#, use interfaces for both the IPlugin (guest) and IPluginHost (host) and guest module writes will inherit from or implement those interfaces. Ideally, the minimal IPlugin interface could be as small as init() and destroy() (if destroy is needed.)
Finally, if starting fresh, you might think about designing your entire application to nothing but the framework and your own pieces will simply be plugins.
The hard part is the registration process. Do you allow files to be uploaded to a web server? Does it write and re-read a config file listing plugins? I haven’t looked at DotNuke or PHPNuke or Typo, WordPress or any of the other ones. But the answer is in there.
Ruby on Rails has a built-in plugin architecture, but not one that you can upload files to, at least not w/o restarting the RoR app iteself, IIRC. It looks in a subdirectory for plugin subdirs for a file called init.rb. It just executes whatever is in that tile.