Choosing a legacy software modernization strategy
We’ve put together this article by talking to the people involved in software modernization projects (in leading positions) here at ObjectStyle.
The goal is to help decision-makers choose an optimal software modernization strategy. The post covers some common use cases and approaches to legacy software redesign. It’s also centered primarily around enterprise software development, because these are the kind of projects we do most of the time.
What is legacy software
The term “legacy software” is usually applied to a software system that was written decades ago in an outdated programming language, using some no-longer-supported framework(s), according to dated design principles, and/or that is currently running in an increasingly unsupportable environment.
When you should upgrade
A reasonable question is “Why touch legacy software if it works?” In reality, it’s not a matter of “if” you should touch it, but rather “when” and “how” you should do it.
Here are some reasons to modernize, ordered by severity (with the most serious ones listed first):
The system contains errors you can’t fix (functions incorrectly, throws error messages, is endangering the survival of your business).
The legacy system is a major blocker (you can’t implement important features or make much-needed performance improvements).
It’s hard to find people to maintain it (the number of people who can work with your legacy software is decreasing quickly; new hires know/want to work with only modern technologies).
It is costly to maintain (and it would be cheaper to modernize, although you may not see ROI immediately).
No one really knows how the system works (the people who built it are no longer with the company; it’s poorly documented and the software is basically a “black box” to you).
In some situations, you can get a pretty accurate estimate on how much it would cost you to keep the old system vs to modernize it. For instance, you can do that easily if you want to migrate to a modern server/environment. It is also quite possible to estimate costs vs. benefits if you sell an end-user product and the changes you make have a direct effect on sales. But it’s more difficult to do that in the enterprise environment. Here, a decision to modernize is often driven by the legacy software being a major inconvenience or a huge cost to the company.
Approaches to software modernization
Now let us describe some common things that companies do to upgrade their software systems.
Breaking a monolith to microservices
Microservices became a “thing” some ten years ago, but it took the developer community many years to learn to use them efficiently. What is a “microservice”? It’s a lightweight application that is relatively independent and can be easily added to or removed from an enterprise system. If your system is made up of microservices, it is flexible, scalable, and easily configurable.
How is this related to legacy systems? In the past, it was difficult for companies to create proprietary enterprise frameworks. They relied on heavyweight “all-in-one platforms” offered by large corporations like IBM or Microsoft. Inside these platforms, apps/modules were tightly linked and formed a “monolith” - one indivisible whole. Some 15 to 30 years ago, this approach was perfectly justified. As new technologies emerged, people started opting for the microservice architecture more and more, until eventually it became a best practice.
When is it a good idea to rewrite a monolith system using microservice architecture? Any legacy platform serves a specific purpose. If you can see that the said purpose is well-aligned with the microservice architecture (can be split into smaller tasks), then it makes sense to do that.
CASE STUDY (here is what we did for one of ObjectStyle’s clients)
Moving to cloud
Another trend is moving your system from a proprietary server to a cloud service like AWS or Microsoft Azure. This has a ton of benefits. You get much greater fault tolerance; it’s up 24/7 and there are no downtimes or maintenance modes - which are the things everybody hates.
Cloud services allow you to reset and upgrade things in parallel behind the scenes. There are various platforms and strategies for doing that. The main goal is to let systems work without failure and make them easier to maintain. If you have a set of microservices, you can easily scale them horizontally (by adding more capacities) or vertically (by adding new functionality) in the cloud. That’s why it makes little sense to move a monolith to, say, AWS without breaking it into microservices beforehand.
Cloud services have also been created with continuous deployment in mind. This means you have the infrastructure that allows you to stand up a new instance of a service, run it in parallel with the current version, and shut down the old one after the new app has been thoroughly tested.
Sometimes, when no source code or no real documentation is available (let’s say, a project had been performed by a mix of vendors who called it a day after delivering the “final product”), it is necessary to reverse-engineer a system to understand its structure. While it’s not really possible to restore the original code symbol-by-symbol, there are various techniques that can help you write very similar code that will do very similar things.
In certain instances, the source code may be available, but it could be outdated (different from the code which powers the current version) or not very helpful anyway. So, reverse-engineering would be a faster/safer option than using the available code.
Reverse-engineering is a good chance to make your code more robust while you are at it and to rewrite the system in a more modern language, framework, etc.
Here at ObjectStyle we have experience reverse-engineering legacy apps for one of the clients. It took a lot of effort to understand how they worked and, eventually, to replicate them in a new, modern environment.
Preventing technical debt
Let’s assume that you’ve just finished upgrading your system (which only happens in the ideal world, really) or that you are a startup and are just beginning to develop your app, so you can’t have real “technical debt” by definition. How do you future-proof your software?
First off, let’s clarify what “technical debt” is. Most software has it to some degree and in some form. In short, this is any part of your system that could be made more compact, faster, better legible, less buggy, written using more appropriate technology, etc.
There are ways to effectively keep technical debt at bay. Here is what you can do:
Explicitly manage “technical debt”
Companies that use good development methodologies always dedicate some amount of time to “reducing technical debt.” You can add “refactoring” tasks to the backlog and have a habit of tracking the size of your debt.
Write unit tests
It’s a good practice for your developers to write a unit test for any new functionality prior to putting it to code. This way, it will be easier to test and port into the existing system.
If you have good unit test coverage, it helps with documenting your software. Well-maintained unit tests can serve as a kind of perennial documentation.
Do continuous refactoring
Refactoring is rewriting code in such a manner as to make it simpler, less confusing, and less verbose. This makes code easier to read and maintain. Code refactoring can improve application performance.
All in all, there are some typical “code smells” that indicate the need for refactoring. In truth, many developers get little to no time for refactoring (because business requirements are usually a priority), so it’s a good idea to periodically allocate time for this activity.
Do continuous integration
In the past, we’ve described how we had set up a continuous integration pipeline on one of ObjectStyle’s projects. The benefits are that you are testing and releasing software nonstop. This ensures higher code quality and minimizes technical debt, among other things.
Take platform approach
Good developers do as they’re told; great developers go an extra mile and always keep in mind that they are dealing with a bigger system. This is the philosophy we live by at ObjectStyle when working with enterprise clients. Always think that it may be necessary to scale or move parts of the system and that you will need to maintain it moving forward.
with ObjectStyleSee our work