"is to allow extensibility to solve other problems later."
"The most successful people are those who are good at plan B." - James York
The extensibility of a design, is a major part of its success and the longevity of SolvingDesign.
An Extensible Design:
- Allows future problems the use of the design artifacts that solve today’ problem.
- Allows customization of the solution.
- Where it’s not possible to close all scenarios, allows these to be found and implemented later.
- May use AgileDesign to ensure a level of abstraction before providing extensibility.
- May use AgileDesign as a means for ExtensibleDesign.
Intent
The Intent is to provide a principle for thinking about the longevity of a SolvingDesign. Solving a problem for the current context, when context can change is where we should separate what changes quickly from those things that can change slowly. We should be able to use ReachableDesign and SolvingDesign quickly, but never to a point when it is always closed. ExtensibleDesign can be implemented extremely quickly and can allow extension of the problem solution.
Motivation
Too many bugs and solutions are fixed, but very soon decay, or open up again. Very often bugs repeat, and bugs evolve into other creatures. We need to get a handle on a problem, and fix it so that it solves the current problem, but is malleable enough to allow the solve to continue easily. The duration of time that the problem remains fixed for, before it breaks again, can be increased by separating code and using extensions.
Solution
In order to Extend a solve, refactoring the area, into smaller code is always recommended.
These should then always have a test or two in place. The ExtensibleDesign, should also allow for the code to be extended.
If the solve continues to break, you need to separate the code out into a separate module, and this will help in the longevity of the solve.
ExtensibleDesign is a means to disconnect an area from other areas, and it helps you define a set interface for the communication.
Use a plug-in pattern, Template Method (GoF), Abstract Factory and abstraction based patterns.
Solution : Build a river
Sometimes code requires a nice stream, just wide enough to separate things. Keep certain classes isolated, and keep others out.
How hard is it for other code to come over and invade us? The wider the river, the harder it will be. This is actually a point of tension. How hard should it be to cross the river (how complex the boundary, and Interfaces, which brings us to the bridge.
You can "build rivers", by separating the code into various modules, or assemblies. Make sure there are Application, Execution, process, or machine boundaries. This is the width of the river.
Solution : Build a bridge
It is often wise to build a bridge, across your river. Use an interface that is not too wide, but you have to understand the traffic that will cross it. If you make your Interface very thin, and specialized, it will most likely be needing a rebuild soon. Instead, make it wide enough to cope with the sort of expected traffic. You will have to become an Oracle, and attempt to see the future.
In AgileDesign, you want to build streams, but with ExtensibleDesign, you want rivers and you want small and large bridges for different kinds of traffic.
if your river is really wide, perhaps you need to build a Web Service, or something less state-ful, and more isolated and singular service-oriented calls. The narrowest is a separate class in a separate dll, that is loaded and constructed when required.
Solution : Dependency Injection
All dependency Injection techniques can aid you separating out the parts that change. Even if its a simple property of type Object that contains a dynamic replacement of its value from a setting in a configuration file, on load, or if its an object passed into the Constructor, the technique on the larger scale, across a boundary is what we call a plugin, or Extensible Pattern.
Solution : Data/Service Mapper
or ServiceLocator Pattern. The simplest version of it, is the idea of having a key/value pair, where the key is the TypeOfData and value is DataServiceClass. So in essence you are via configuration mapping a Person object to a PersonXmlSerializer, but can optionally modify the config to point it to PersonMySQLSerializer or PersonSqlSerializer.
Solution : PlugIn Patterns, Inversion of Control
I always build solutions with Factories and extensible points. Often these become a lightweight Framework within the Application. A plug-in Pattern is not dissimilar. A Plug-In requires at its minimum, an Interface such as IPlugIn, a Factory within the Application, which uses some sort of MetaData to load the IPlugIn concrete implementation.
Solution : Solve problems Later
By not having to recompile your project, but by merely modifying a small dll, and placing it into a directory, which then changes the calculation, is an "extensible bug fix", rather than a standard code editing bug fix. Have the capabilities of overriding a default implementation can be tremendously useful, especially in an area, where a large percentage of change might occur over time. Having a Business team change their mind 2 months of using the system, is not uncommon, having the ability to change something easily is always better.
Keep in mind that a system, built entirely in the fashion can be tremendously abstract, difficult to follow, possibly harder to debug, and perhaps difficult to maintain and control. There are also security issues.
Applicable Patterns
Abstract Factory (GoF)
Factory Method (GoF)
Builder (GoF)
Template Method
Adaptor (GoF)
Bridge (GoF)
Mediator
Composite (GoF)
Decorator (GoF)
Proxy (GoF)
Chain of Responsibility (GoF)
Visitor (GoF)
Creator (Grasp)
Low Coupling (Grasp)
High Cohesion (Grasp)
Polymorphism (Grasp)
Indirection (Grasp)
The Open Closed Principle (SOLID)
The Liskov Substitution Principle (SOLID)
The Dependency Inversion Principle (SOLID)
Pair programming (XP)
Embracing change (XP)
Sprints (SCRUM)
Develop Overall Model (FDD)
ConflictsSolvingDesign, ReachableDesign
ComplimentsAgileDesign, Maintainable
Ammerse Principles