What to do with your legacy monolith
This post was originally published on LinkedIn
Are you working at a company that has a legacy monolith that you’d like to get rid of?
Are you sure?
Maybe you think you should migrate it to a microservice-based architecture? After all, that’s what all the cool kids are using these days, isn’t it?
Before you do that, just stop and think a moment about what it is you actually need, and what problems you are trying to solve by considering what I presume would be a fairly major transformation project. Start by asking yourself a couple of questions:
Is my system really legacy?
There’s a lot of confusion around as to what legacy actually means, and a lot of the time the word is thrown into the mix by architects, managers, CIOs, business folk and others that perhaps don’t really understand what system they currently have. When this happens it is widely assumed that appending the label “legacy” to something will automatically make everybody assume it is bad, and something should be done about it immediately.
This is the first myth that comes from not understanding what “legacy” really means, so let’s just be clear about what it doesn’t mean.
I mean, it can, sure. A legacy system can be a bad thing, but it doesn’t have to be.
So what do we mean when we talk about legacy systems?
A literal definition of “legacy” might be “inherited”. In the world of IT, this might mean it’s an old system that was put in place by people that no longer work there.
OK, fine, but then how many systems in the world count as legacy then? Given the turnover rate of IT people, my guess would be most of them. This in itself is certainly not enough to brand a system as legacy, and certainly not enough to warrant dropping a lot of time, energy and cash on replacing it.
How about a less literal, and more useful definition?
“In computing, a legacy system is an old method, technology, computer system, or application program, of, relating to, or being a previous or outdated computer system, yet still in use”
To take this further again, in his book Working Effectively with Legacy Code, Michael Feathers provides a more succinct definition, that is probably more useful for anybody in the real world.
“To me, legacy code is simply code without tests.”
– Michael C. Feathers
Let’s take a look at some examples.
Example 1 - “Inherited”
A 7-year-old system written largely in Java. This was the baby of the CIO at the time. The company has gone through 2 more CIOs since then, a couple of CEOs, and there’s nobody left in the IT department that worked on the original development, but it runs well and has pretty decent test coverage. When business come up with the occasional new requirement, there are enough Java coders at the company to handle it.
Example 2 - “Old tech”
A 30-year-old backend system written in COBOL. At one point this was the entire CRM monolith, but some time back it was relegated to backend only, and simply manages data via APIs to more modern front-end systems. All the APIs have full test coverage, and there are even some unit tests floating around for a couple of the more complex areas. There is one COBOL programmer at the company that handles the very occasional change request.
Example 3 - “Code without tests”
This is basically example 2, but without any tests. Perhaps it was never upgraded to be backend-only, and is still the primary CRM tool for the company? It works just fine, but people are afraid to touch it because they don’t really understand it, and COBOL consultants are expensive these days!
I think we could probably all agree that Example 1 isn’t really a problem. There are no problems finding decent Java coders, it’s not a problem implementing new requirements because there is decent test coverage. Perhaps you have a case where modernising your delivery pipelines may payoff - better CI/CD flows to automate the testing and deployment - if this is not already being done, but change the core system … why?
Looking at Example 2 we can definitely see some issues, but not showstoppers. Changes can be made and tested, and new requirements can be handled. The only real issue is how long are you going to be able to keep that COBOL programmer on the team, and can you afford an expensive consultant if they leave?
Probably you want to start thinking about moving away from COBOL here, but exactly how urgent this is will depend on a whole load of other factors. Perhaps only small parts of this system need to be moved out, and the rest of the functionality will deprecate naturally over a span of 5-10 years? Think carefully about all the factors, costs and risks before moving ahead.
Now, onto Example 3. This is a clear example of a legacy codebase that you almost certainly need to do something with as soon as possible, but even this may not be sufficient to warrant throwing all that money at a giant transformation project. Perhaps getting this system to a similar state as Example 2 would be enough for the moment?
Now, let’s look at the question you should ask yourself about monoliths …
Why do I want something other than a monolith?
The answer to this appears to be self-evident to many, and the core driver for giving the go-ahead to a lot of large transformation projects - monoliths are bad, right?
Well, they can be, sure. But they’re not bad just because they’re monoliths!
To start with, there are many different types of monolith, some of which even resemble a more contained version of a microservice architecture. A well-designed modular monolith might be exactly what you need! On the other hand, it seems that the words “monolith” and “legacy” are interchangeable, which I suspect is what leads to a lot of the confusion.
A monolithic system certainly can be a legacy system as well, but it doesn’t have to be. If you have decent test coverage and the resources available to make changes, then your monolith is most likely not causing you any problems.
If, on the other hand, your monolith is a big ball of mud, then yes, this probably counts as legacy and you should be looking to do something about it. In this context, a big ball of mud refers to the fact that nobody has really understood the entire system for some time, so there is code duplication, data redundancy, giant processes that do 101 things that would be better split into smaller processes, and - of course - no real test suite to speak of.
This is a bad monolith, though - to reiterate - it’s not bad because it’s a monolith. It’s bad because it turned into a legacy system by any definition of the word some time back, and now most people are terrified of touching it lest they break some core piece of functionality and cost the company a lot of money!
OK, so when should I look at changing things?
Good question! I think if all you’re hearing from people is that:
“We need to get rid of this monolith!”
“We can’t have a legacy system!”
“We need to use microservices - that’s the modern solution!”
… then you should start questioning whether there’s really an issue. Perhaps there is, but dig deeper and get the facts first before you throw a lot of money at it. If, on the other hand, you have problems with things like:
Long delivery times for changes because everything needs testing by hand
Reluctance to change the system because everybody is frightened of breaking it
Difficulty finding resources to maintain the current system due to old tech, and the fact that a lot of people that can do it have actually retired years ago
Proprietary technology that comes with high licencing costs
… then you might want to start looking into alternative solutions. Of course, this isn’t a comprehensive list of the problems you might see, but it’s certainly some of the most common ones, and if you have problems I’d expect at least one or two of them to be on this list.
I think we need to change, what should we do?
If you think you have a need to modernise and you’re wondering about this giant transformation budget that’s just landed on your desk for approval, think about the following things before you sign off on any plan:
Don’t change based on the “need” to move to a modern architecture. Microservices are not a panacea, and will not help you just by being microservices. Consider alternatives, including the possibility of a new monolith.
Make sure you involve the people with the domain knowledge.
Get a clear understanding of the business processes you want to move out of the legacy system before attempting to move them.
Be careful working “agile” when building a new system from the ground up. Some things require a larger understanding of the whole if you don’t want them to come back and bite you later.
Think about how quickly you want to move. What are the critical processes you should consider moving first? How much, if anything, could be left behind in the old system to die off naturally?
Could you give yourself some more time to deal with all this in a sensible way by spending a little money on the legacy system: putting some tests in place for core processes, building some new APIs that make it easier to cutover, tidying up some of the really messy code to break it into functions that better align with proposed service boundaries.
I would highly recommend the following. The Michael Feathers book is an old one, but still relevant. The Sam Newman books are easy to understand and will give a good insight into the challenges for people at all levels of the organisation.
- Working Effecively with Legacy Code, Michael C. Feathers
- Building Microservices: Designing Fine-Grained Systems, Sam Newman
- Monolith to Microservices: Evolutionary Patterns to Transform Your Monlith, Sam Newman
- GOTO Conferences, YouTube
Photo: Tim Jarvis