How to upgrade your legacy systems
A legacy system is a software system that was in use for much longer than it originally expected to be. These systems have been through many years of changes and updates, resulting in very complex code bases. As they grew, the development teams responsible for them grew as well. We saw much bigger requirements getting implemented in these systems without re-factoring or reviewing the existing code base.
Legacy systems are often hard to maintain and hard to develop further on if we ignore their poor design choices. Refactoring such a large application would mean changing several (if not all) of its modules and will result in considerable amount of time and money invested into this project by the business side – both factors can make or break any software upgrade decision.
Over time, these ageing systems evolve into “legacy systems” because they don’t provide the same flexibility and maintainability they used to when their requirements were initially implemented. This is mainly due to the fact that in order to accommodate for changes in functionality, it became necessary to add several workarounds and even duplicated code. In some cases, specific modules of a legacy system might be obsolete – i.e. new business functionalities will not be supported by them even if they would technically fit our needs.
WrapperFacade design pattern as described above – let’s take a look at each one of them separately to see why.
Once again, since this is Java language, this cannot be our choice for storing wrapper facades’ implementations. Besides the fact that member classes cannot have any constructor parameters, there is another problem with using private classes introduced by language feature called “inner classes”. In short words inner class represents a class defined inside another class – while this might sound like a bad choice for creating wrappers, you should consider using protected instead of private whenever possible (which allows using protected members directly).
As you can see from the example above, our initial goal was to delegate all requests passing through getSomething method straight into code which is responsible for actual data processing – thanks to inner classes there is no way we can do that without breaking encapsulation boundaries defined by language! Finally, even if we could make sure that both parts used inside wrapper facade were always available (by e.g. delegating calls to them through other classes), our object would be still tied to one particular class – this is unacceptable if we want to provide a separate set of wrapper facades for each service method wrapping different implementation.
This choice sounds much more promising since it allows us creating an implementation once and then sharing it between all wrappers which require same functionality. However, in reality there are two problems with using public methods:
1) they usually have some additional requirements before being called (e.g. security annotations or transaction attribute); 2) any change in method declaration can easily break existing code calling these wrapper facades. In fact, the latter case actually renders this approach useless because even if we introduce new wrapper facade implementation today, we can be sure that some other team in our project will break it tomorrow by changing the method signature.
Although we managed to provide two different wrappers for given service method (and even more than one of them), this approach is limiting us from creating a uniform set of wrapper facades – every new facade requires us to change existing code which uses them!
As far as Java language is concerned, this is actually the only place where we can delegate instantiation of our facade’s implementation without breaking encapsulation boundaries! Unfortunately, since constructors are not inherited by sub-classes (again, this might sound strange if you never used any object oriented language before) there is no way for our subclass to call parent’s constructor or even access its members. In case of WrapperFacade pattern, this means that we cannot provide multiple implementations through one common interface but at least it allows us to keep all code inside separate inner class.
As you can see, thanks to usage of constructor we can solve the problem we had by defining methods with additional requirements. However, we still cannot create a uniform facade in case we want to provide multiple implementations for different service classes and even in case of just one implementation we need to duplicate code which is supposed to be shared between all wrapper facades (e.g. print statement or security annotation).
What if we could offer multiple implementations for given interface without modifying existing code using our facade? It turns out that this is possible thanks to Java’s indirection mechanisms which allow us to provide runtime polymorphism – instead of specifying concrete type of implementing class when creating reference, we can pass it through factory object! Sounds cool but how does this actually help us in practice ?
In above example we have a utility factory which can take any service interface and create a facade for it on the fly! By using standard mechanism of lazy instantiation, we make sure that each time when requested service is actually going to be called, some wrapper instance is going to be created (you may think about improving this code by taking care of providing single or more efficient mechanism of creating wrapper instance, but for sake of clarity let’s leave it as is).
As you can see, there is no need to provide concrete implementation of any service – our factory takes care of every aspect by only knowing service interface! Most important part of this indirection mechanism is that clients are not aware about implemented services! This means that once we decide to add support for another service, all code which uses facade does not have to be modified at all! As a bonus, thanks to usage of interface, we are able to create unit tests which can take dependency on all supported wrappers.
As you might have noticed during the course of this post, thanks to usage of factory approach, our code became cleaner and easier to read. Of course there is always a price for everything so what about performance? Well, as it turns out, thanks to lazy instantiation feature provided by Java’s indirection mechanisms using factories gives us similar amount of overhead as using inheritance with interface would do – language itself takes care of creating new reference objects on demand! By solving some issues regarding dynamic dispatch mechanism used in case of interfaces, wrapper facades offer an easy way to mix static polymorphism with runtime polymorphism which leads into clean & maintainable code. Contact Rotherham Apps and we can help you upgrade your legacy systems.