Extensibility Anti-Patterns and Best Practices
Anti-Patterns
Determining valuable points to allow for extension is as much art as science. Creating an unused extension point is wasteful but difficult, if not impossible, to predict. This in and of itself is not an anti-pattern. But exploding the engine into a web of extension points makes the engine very difficult to debug – so this does become an anti-pattern.
Building the engine with an architecture that doesn’t consider extensibility is the true anti-pattern. Many times, engines are developed quickly to satisfy a contract. Extensibility is not part of that contract, so it is skipped. But the architecture of the engine should be structured such that developers can easily see the extensions.
Best Practice
Read, Process, and Write should be in separate classes. Each data element read should be in a separate class. Each step of processing should be in a separate class. Each data element written should be in a separate class. These classes should be created by a factory class. The factory class is where the decision to serve the base class or an override is made.
NOTE: Even if plugins aren’t created for an engine, if the architecture is followed with separation of responsibility and factory classes, then extension points are easily created.
With each of these in different classes, each class could be replaced. In fact, if every class is replaced, one could change the entire nature of the engine.
Simple plug-in architecture is the preferred technique. Each Module has a Module Context Listener where the engine can add an ArrayList of their plug-ins. Higher-level modules and EPTs can add their version of the plug-in to this list. The engine looks to this ArrayList to see if there’s a relevant plug-in of each type. If the plug-in exists, then it replaces the class.