How to use the Strangler Pattern when migrating your legacy software system.
In my last blog post about the Strangler Pattern, I looked at Why and When to Use the Strangler Pattern. If you have not read that article yet, then I would encourage you to go and have a read through it first. This article will make much more sense in the light of that.
Assuming you are familiar with the Strangler Pattern, why and when to use it, and that you have decided to employ it in the process of modernising your legacy software application, we will now proceed to considering a hypothetical life-example. Let’s say, you have a business web-based application that has served you well for the past 15 – 20 years. Now though, the application in question is perhaps more of a hindrance than an asset. Let’s say it is slow, it fails often, it is expensive to maintain, there are perhaps security concerns, and support is much more troublesome due to frameworks and components that have been dropped by the corresponding vendors. This is a typical situation that businesses find themselves in all the time due to ageing software.
As a side note, it is no surprise to anyone that technology moves on at a scary pace. Technologies come and go out of fashion at an alarming rate and turning a “blind-eye” on this issue, risks obscurity. So, it is important.
Step Number 1
Given that the Strangler Pattern is a migration-type approach whereby “sections” (I like to call them modules) are migrated from the old, to the new, one by one, in succession, it is important to know what those modules are. The very first step is to dissect the legacy system into separate logical modules. For example, one module could be the User Management. Does the legacy application consist of some form of a login page? Does it allow for roles to be assigned to users. Are there access levels? Can you create new users and roles? All of this functionality pertains to the user Management module.
Or let’s say the legacy application allows users to extract various reports and exports. That would clearly be identified as a Reporting module. You can then spend some time putting down a bullet-point list of all the reports and exports that are currently provided by the legacy system. Then identify which ones are still useful and to be ported over and which ones are not. Then, you have another clearly defined module which can be migrated as an overall project milestone.
The aim of this step is to finish with a list of logical modules which require migrating, and the features against each that is still in use. For example…
- User Management
- Create Users
- Create Roles
- Profit and Loss report
- Stock levels export
- Raise invoice
- Mark invoice as paid
Step Number 2
Once we have the list of modules and the features under each module that we want to keep, we now need to asses the dependency matrix. Which module depends on which, and how strong is the dependency? The aim of this step is for us to come out with a logical order in which to migrate the modules. We are trying to sort the modules in a less problematic to more problematic order. Less problematic meaning the least amount of dependency on other modules. For example, the User Management module has relatively few if any dependencies on other modules. It only answers for authenticating and authorising a user. Whilst the Billing module depends on many things like the customer, the supplier, the product being sold or the service being offered, and so on. So you will want to do the Billing module last because by then, hopefully all the dependencies will be in place.
What we do not want to do as part of the migration project is to have to migrate bits of different modules at the same time. This will make the life of the users very difficult, because they will not know which feature of the module should be used where, in the new system or in the legacy system. It adds confusion and irritation. This step aims to remove as much of the friction (resistance) as possible from the whole process. It is virtually impossible to remove all friction from the process, but the less the better. That is why, it is important to come out of this step with a very well thought through order in which the modules will be migrated across. That way, the users, as long as they know it is only temporary, will be ok with using a module in one place and another module in another place. For example, add a new user to the system in one place and then run some reports in another place. It is manageable. As long as the user does not have to create the user in one place, then in another place give them some roles, and then finally in another place enable them for 2FA, and finally resetting their password is back to where they started. That would be frustrating. So, make sure you get this step of the project right, and you will eliminate a lot of resistance from the users, which is crucial to the success of a project, not to mention the state of your morale.
Step Number 3
Of course, by now, you know what you are doing and you know how you are going to do it, the work can begin. One question should be imprinted in your mind, and that is, what if you need to roll-back? It is so tempting to change the database, and other things as you develop the new system, but what if you need to roll back? Will the legacy system still be usable if for whatever reason, you need to roll back? All the steps taken as part of this step need to prioritise backward-compatibility. As you have migrated a module across, both the legacy system and the new system should be usable, still. Many times, you will publish a new module, and then bugs come up, and a new user cannot be added, or a role is not working, well, and then the users can still do that task through the legacy system, until a fix is published. This approach, although more long-winded and expensive, it will ensure two very important things, backward compatibility in case of a roll-back, and business continuity, in case of failure in the new system. Until the new system has found its feet, it only has the old system to lean on.
Another important thing to remember during this step is to involve the users as much as possible. Assumptions can wreak havoc when delivering a new software system. Do not assume, but get the users involved instead. Bi-weekly meetings work great. Progress is communicated to the users and the users get the chance to shape the new system. There will be a sense of ownership from the user’s behalf which will serve well when trying o drive adoption. Getting the users to really adopt a new system, is where great and useful feedback will come back and then success is that much more forthcoming.
A final word of advice for this step is to try and make it easier for the users to use both system simultaneously. For a period of time, as modules are being migrated, the users will have to use both systems at the same time. Will they have to log into different computers? Will they have to have many different tabs open in front of them? Will they have to keep refreshing (or remembering to) some windows? All of these things add to frustration and friction when trying to push the new system out. Make it easy for the users to switch between the new and old with perhaps having them logged into to both. Or make it possible for them to use it in the same window. Anything would be very useful to the end-users during the transition process.
Step Number 4
By now, hopefully the legacy system is not needed or used anymore. But now, you will find some die-hard users who do not want to move to the new and they will keep using the old system until it is physically taken away from them. They will then for months find and if can’t find then make-up things that are wrong with the new system and how the old was so much better. There is no way to avoid users like that, so you go with the majority. But one thing these die-hard legacy system users cause is to miss things. Because they do not use the new system, they will not voice anything untoward in the new system. So, when you think you are done, you are not done yet.
The way to deal with “migrated” (as far as you are concerned) modules, is to switch them off, disable them, hide them, or something like that, where the users cannot use them anymore in the new system. Then, when a user is forced to use the functionality in the new system, things will come up that are either missing or do not work properly. Then, you can re-enable (temporarily) the module in the legacy system, until a fix is published. This is the only way to prevent those go-live issues.
Then, once the legacy system has been switched off (on stand-by) for a few months, without the need to switch it back on again. You can safely assume that you have arrived. The only thing left now, is the database.
I have not put the database as a step in the process because it depends. Unless you want to completely change the database technology, I would not consider it a separate step in the whole project. For sure, you will definitely want to tidy-up the database schema given that many things in it are probably no longer used, needed or even retainable by law. But whatever your case is, I would do it as the very last thing, after the legacy system is laid down to rest for good. Because most database changes may affect the code of the application, you do not want to change code in two separate systems, especially legacy code. Legacy code should only be kept as a reference point to test the results that the new system gives. The legacy system is in most cases your only source of documentation about how a given feature should work. Do whatever you need or want to do to the database once the legacy system is completely out of the picture for good.
One friend software developer once told me, “do not be afraid to be using two different databases as part of the migration process”. Meaning, save data to both databases as functionality is being migrated across, so that in the end, you can just shut down the old database along with the legacy system. That is good advice, but it requires more care and diligence. I will re-iterate the same advice, but I will add this at the end, “only if you have to”.
So, there you have it. As simple as that. Well, maybe not as simple as that, but one big advantage of doing it this way is that the system is being tested and embedded in gradually. That means that errors are caught in a manageable manner and sorted. By the time the system is all migrated, it is 80 – 90 % tested in the real-life environment. Nobody likes having a big go-live party, only the next morning to wake up to the news that the new system has exploded and there is no roll-back option.
Choosing the right approach for the right case, is half the battle won.