A simple plugin architecture

One rule to live by, KISS

Posted on March 17, 2014

While designing an application, it is often desirable that this application can be easily extensible, even by a third party plugin. Now, you might be pondering about the benefits of an application using third party plugins. There a more than a few advantages of using such an architecture. A few most important of them are

  • A user can customize the application as he likes if relevant plugins are available (or he can develop one).
  • A developer does not have to write every functionality imaginable all by himself. He can easily let other people develop features as they want. It is a win-win situation for both of the parties.
  • An application can be packaged with minimum bloat as the user gets the choice to pick up his own tools.

After being convinced about the merits of such an architecture, we should focus on how to do this. There might be several ways of doing that, depending on the design philosophy and other constraints. However, we would have a look at one of the simplest and most common ways of enabling third-party plugins. In our this simple scheme of things, we would have to lay down few rules first. (We would later see why is that necessary)

  • A plugin has to follow the API that developer has exposed to the outer world.
  • A plugin should have an action or event specified with it (actions or events are specified by the developer like UPDATE_ACCOUNT etc) which would describe the trigger point for it.

Now, you must be wondering that this is getting way too abstract and going all over your head. That is why we will try to understand that with an example.

Suppose, you have a framework for developing your application. You have specified that plugin should extend base class BasePlugin

abstract class BasePlugin {
      abstract public function execute($info);
}

Now, we can define a plugin. Let us call it EscapeOutputPlugin and what it does is escape the output being sent.

class EscapeOutputPlugin extends BasePlugin {
      public function execute($output) {
             return htmlentities($output, ENT_COMPAT, 'UTF-8');
      }
}

As the responsible developers in this example, we have also defined an event called PREPARE_OUTPUT which is triggered before the output is being sent. We can then tell our framework to register EscapeOutputPlugin on PREPARE_OUTPUT (via some registerPlugin method or adding it to some config). In our application, when we receive an event we can trigger the plugins attached on it. Thus, when PREPARE_OUTPUT event is triggered our plugin is executed along with others if any registered on the same event.

We also need to look at safety concerns. We should be cautious about not leaking unwanted info to external plugins otherwise consequences can be pretty darn. Like every safe society, our application should also have well defined rules. We do not want to give access to sensitive data or grant for admin action to any third party plugin so we should put checks in place to ensure that.

Now that we have learnt the ancient art of enabling plugins for our applications, let us make world a better place.