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.

It is possible to refactor your legacy system without actually touching its core functionality or features provided by its modules. By providing additional layers of abstraction on top of a legacy application’s code base, we can add new functionalities and refactor existing ones without changing the older code. Instead of modifying existing classes, we’ll use a technique called “Wrapper Facade” to create new classes that will intercept calls to legacy application’s core modules and then either return their correct data or pass them on to the legacy system unchanged and perform required modifications afterwards.
A wrapper facade is implemented wrapping an already existing class with another one. A wrapper facade provides some enhancement over the original class it wraps – in our case, we’ll provide basic logging capabilities for every method executed by every module of the old system (without actually touching its source). This will give us visibility into how our systems behave at runtime which is especially important if several developers are working within one large legacy code base.
Although both techniques are known as “facades”, there is a very important difference between the two approaches that I’d like to point out. The original Facade Pattern provides an additional abstraction layer on top of existing system’s functionalities hiding its complexities from the user, thus simplifying its usage interface. On the other hand, wrapper facades don’t actually change any behaviours or functionalities of the system they wrap – instead they provide additional features to it without changing its public interface at all. That’s why we’ll refer to them as wrapper facades instead of using more generic term “facade”.
Wrapping our legacy application classes is just one part of refactoring process that can help us upgrade systems which might have been written several decades ago. We’ll also discuss how to introduce a proper dependency injection model into existing code base, thus creating an environment where new features can be easily added without any change within the older code.
Before we go any further, let’s start by discussing what these wrapper facades actually do for you – this is especially important if you’re not familiar with design patterns and code refactoring.
At its core, dependency injection consists of introducing additional classes into your legacy application’s source code base which will help us inject dependencies in the right way – these are usually called “dependency injectors”. We can either use an actual Java-based framework for this purpose or implement it by ourselves using only the language’s core features. In this way it is possible to introduce wrapper facade design pattern into existing system using only Java language features without any third party library whatsoever. Wrapping an object with a wrapper facade is quite straightforward process and consists of two steps: first, we need to pass an already created instance of wrapped object into constructor of our WrapperFacade , then store it within one of its members (which we’ll refer to as “backing field”). Since this is a simple example, we can even omit the constructor altogether by using default one provided by Java language.
You can notice that WrapperFacade doesn’t actually change behavior of Object it wraps – instead it only exposes its functionality through new wrapper interface, which consists of single method returning String . At this point you might be wondering why would anyone want to use such an unnecessary complicated design pattern – after all it’s just additional indirection which adds nothing but some syntactic sugar into code base. Let me explain where does wrapper facade come into play before looking at more realistic examples showing how they are used in real projects.
When working with legacy systems, there are scenarios where very often you need to perform some types of operations (usually, very specific ones) on already existing objects – these are usually the only cases where wrapper facades actually make sense. My personal opinion is that each time you see yourself tempted to call one of following methods instead of directly calling what these wrappers wrap, you should consider introducing new wrapper facade instead:
One can argue that sometimes even this list might be incomplete – I just wanted to give examples showing how these design patterns look in practice and why would they be beneficial for your refactoring project. Finally, let’s take a look at how we can introduce these wrappers into legacy code base without modifying actual code written by original application’s authors.
When dealing with Java language, typically there are only three places where we can put these wrappers (I’m not considering code generators which I’ve seen in some projects – they are usually much more complicated to use and work with): private members, public methods and constructors. Unfortunately, none of them allows us to exactly implement WrapperFacade design pattern as described above – let’s take a look at each one of them separately to see why.
private members
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).
private class Wrapped extends Object { … } public String getSomething(String input) { System.out.println(“Getting something…”); return new Wrapped().getSomething(input); }
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.
public methods
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.
public class WrapperFacade { … public String getSomething(String input) { System.out.println(“Getting something…”); return new Wrapped().getSomething(input); } } public interface Wrapped { … } public class SometingWrapper implements Wrapped { @Override public String getSomething(String input) { // when calling super implementation, make sure to add security annotation System.out.println(“Calling super implementation”); return super.getSomething(input); } … }
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.
public class WrapperFacade { private Wrapped wrapped; public WrapperFacade(Wrapped wrapper) { wrapped = wrapper; } public void doStuff() { System.out.println(“Inside WrapperFacade: ” + wrapped); // we can always access this inner class through it’s parent! System.out.println(“Inside Wrapped: ” + wrapped); … } }
public class SometingWrapper implements Wrapped{ @Override public String getSomething(String input) { // when calling super implementation, make sure to add security annotation System.out.println(“Calling super implementation”); return super.getSomething(input); } … }
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 ?
public class WrapperFacadeFactory { public static void registerWrapperFacade(String serviceClass, WrapperFacade facade){ ThreadLocal wrapped = new ThreadLocal(); wrapped.set(new DefaultWrapping()); facade.registerServiceImplementation(serviceClass); } }
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).
public class Example { public static void main(String args) throws Exception { Wrapped wrapped = WrapperFacadeFactory.getWrapperFor(SometingService.class); wrapped.doStuff(); } }
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 us for more info.