Plugins #
Overspecialize, and you breed in weakness. Customize the system through attachable modules.
Known as: Plug-In Architecture [FSA], (misapplied) Microkernel (Architecture) [POSA1, POSA4, SAP, FSA], Plugin [PEAA], Addons, Strategy [GoF, POSA4], Reflection [POSA1, POSA4], Aspects, Hooks.
Variants: Hexagonal Architecture and Microkernel got dedicated chapters. Plugins have many variations.
Structure: A Monolith extended with one or more modules that customize its behavior.
Type: Implementation, extension.
Benefits | Drawbacks |
---|---|
Some aspects are easy to customize | Testability is poor (too many combinations) |
The customized system is relatively light-weight | Performance is suboptimal |
Platform-specific optimizations are supported | Designing good plugin APIs is hard |
The custom pieces may be written in a different programming language or DSL |
References: [SAP] and [FSA] mistakenly call this pattern Microkernel and dedicate chapters to it.
Most systems require some extent of customizability all the way from the basic codec selection by a video player to the screens full of tools and wizards unlocked once you upgrade your subscription plan. This is achieved by keeping the core functionality separate from its extensions, which are developed by either your team or external enthusiasts to modify behavior of the system. The cost of flexibility is paid in complexity of design – the need to predict which aspects should be customizable and which APIs are good for known (and unknown) uses by the extensions. Heavy communication between the core and plugins negatively impacts performance.
Performance #
Using plugins usually degrades performance. The effect may be negligible for in-process plugins (such as strategies or codecs) but it becomes noticeable if inter-process communication or networking is involved.
The only case for a plugin to improve performance of a system that I can think up is when a part of the client’s business logic moves to a plugin of a lower layer of a system. That is similar to the strategy injection optimization for Layers. Real-world examples include:
- The use of stored procedures in databases,
- HFT rules and price tables uploaded to a network card or FPGA,
- Customization of supplier services for varying needs of their client services in Domain-Oriented Microservice Architecture.
Dependencies #
Each plugin depends on the core’s API (for Addons) or SPI (for Plugins) for the functionality it extends. That makes the APIs and SPIs nearly impossible to modify, only to extend, as there tend to be many plugins in the field, some of them out of active development, that rely on any given method of the already published interfaces.
Applicability #
Plugins are good for:
- Product lines. The shared core functionality and some plugins are reused by many flavors of the product. Per-client customizations are largely built using existing plugins.
- Frameworks. A framework is a functional core to be customized by its users. When shipped with a set of plugins it becomes ready-to-use.
- Platform-specific customizations. Plugins allow both for native look and feel (e.g. desktop vs mobile vs console) and for the use of platform-specific hardware.
Plugins do not perform well in:
- Highly optimized applications. Any generic code tends to be inefficient. A generic API that serves a family of plugins is unlikely to be optimized for the use by any one of them.
Relations #
Plugins:
- Implement Monolith or sometimes Layers.
- Extend Monolith or Layers with one or two layers of services.
Variants #
Plugins are highly variable and omnipresent if we take Strategy [GoF] for a kind of plugin:
By the direction of control #
The terminology is not settled, but according to what I found over the Web:
- True Plugins are registered with and called by the system’s core, they may call back into the core or return results – they are parts of the system.
- Addons are built on top of the system’s API and call into the system from outside – they are more like external Adapters for the system.
By abstractness #
A system may use plugins that are more abstract than the core, less abstract or both:
- High-level plugins tend to be related to user experience, statistics, or metadata. They use the core in their own business logic. Addons belong here.
- Low-level plugins encapsulate algorithms that are used by the core’s business logic.
- Some customizations require multiple plugins: a high-level user-facing addon may rely on algorithms or pieces of business logic implemented by several complementary low-level plugins.
By the direction of communication #
A plugin may:
- Provide input to the core (as UI screens and CLI connections).
- Receive output from the core (e.g. collection of statistics).
- Participate in both input and output (like health check instrumentation).
- Take the role of Controller (Orchestrator) – the plugin processes events from the core and decides on the core’s further behavior.
- Be a data processor – the plugin implements a part of a data processing algorithm which is run by the core. This enables platform-specific optimizations, like SIMD or DSP.
By linkage #
Plugins may be built in or selected dynamically:
- Every flavor (e.g. free, lite, pro, premium) of a product line incorporates a single set of plugins (configuration) built into the application.
- Other systems choose and initiate their plugins on startup according to their configuration files or licenses.
- Still others support attaching and detaching plugins dynamically at runtime.
By granularity #
Plugins come in different sizes:
- Small functions or classes are built into the core. They seem to implement the Strategy [GoF] / Plugins [PEAA] design patterns.
- Aspects, such as logging and memory management, pervade a system and are accessed from many places in its code. Reflection [POSA1, POSA4] probably belongs there.
- Modules are plugged in as separate system components. This kind of Plugins matches the topic of this book and is further developed by Hexagonal Architecture and Microkernel.
By the number of instances #
A plugin may be:
- Mandatory (1 instance), like a piece of algorithm used by the core for a calculation.
- Optional (0 or 1 instance), like a smart coloring scheme for a text editor.
- Subscriptional (0 or more instances), like log output which may go to a console, the system log, a log file or socket in any combination, or to all of them at once.
By execution mode #
Plugins may be:
- Linked as a binary code called from within the core.
- Written in a domain-specific language (DSL) and interpreted by the core.
- Communicated with over a network.
Summary #
Plugins allow for customization of a component’s behavior at the cost of increased complexity, poor testability and somewhat reduced performance.