Modular Application Architecture - Considerations on Design Patterns
This is the fifth post from a series of posts that will describe strategies to build
modular and extensible applications. In this post we will take a general overview on how some popular design patterns
and things to keep in mind when creating plugin based applications.
In the previous posts we saw
the "Event Manager" (in reality a variation of the Mediator pattern),
the "Pipeline" (in reality a variation of Chain of Responsibility pattern)
and the use of inheritance to build plugin systems.
Many of the plugin systems are just customizations of popular design patterns.
Anthony Ferrara (alias ircmaxell),
in this post blogged
about the use of software patterns to implement plugin-based architectures.
It is a great article and I suggest everybody to read it.
As it is clear from the article, each of this software patterns has a specific use case
and the choice of which one to use depends on which the of integration we want allow for the future plugins.
Recap
- The Observer and Mediator pattern
allows you to have communication between independent objects.<br>
Is one of the most popular patterns when building plugin-based systems that allows to add or change functionalities.
The application has still full control on what plugins are able to do. - Strategy, Decorator
and Chain of Responsibility patterns
are convenient when one of the plugin should be allowed to change or the behaviour of one functionality
or to implement missing functionalities. - Inheritance combined with
the Template method pattern is useful when
we want to grant to a plugin full control over the application.
The plugin replaces the application code with its code.
Use cases
All of this patterns are extremely powerful and have they specific use cases. Most of them can be also implemented
in a not-object-oriented way. As example:
- The Wordpress theme system can be seen as a "Inheritance+Template method" based system
- Drupal and Wordpress use the Mediator pattern to implement most of their plugin systems (most of it was procedural code)
Tips
- One one fundamental point to make a
plugin system effective, is the way how the application allows to
register and
configure plugins. Most of the power of a
good plugin system comes from a good registration and configuration mechanism.
The more a plugin is able to "hook" into the core of the application the more functionalities will be able to provide.
On the other hand, the way that the plugin uses to "hook" into the core should not be "hacky", should be simple and
should be the same used by the application core to offer its core functionalities.
A good example in my opinion can be the Symfony's bundle system.
It uses extension points
and service tagging
to allow to plugins (bundles) to register their functionalities in the same way used by symfony itself.
- Another tip is to avoid imposing constraints when not necessary.<br>Can be tempting to offer at application level
some "standardized" control panel or storage to configure the plugins... please don't.
Sooner or later there will be a case that will be not supported by the "standardized" format you decided.
Most likely you will end up in this scenario
and you will have to edit the "standardized" format you decided.
The application core should to only the minimum necessary.
Conclusion
In this article we saw some use cases for common software design patterns and some other
considerations to keep in mind when building plugin based systems.<br>
A part that is missing from this series of blog posts (and will be covered in the next post) is
how to deal with static assets (as images, css, files).
Hope you enjoyed this article and if you have some feedback, do not hesitate to leave a comment.
Excellent post I’ve been doing this for years without knowing the exact name of the patterns with a system to render forms on Wich every widget is a plug-in with hooks therefore extensible
Kudos!