I have been working on some projects, where we replaced 10 to 20-year-old enterprise applications like customer portals or internal business applications. Actually, I found this very impressive since those applications have been running for more than 15 years and they are doing their job. But still, after such a long time they are reaching their end of life. It is always the same reason why we get paid to replace those old relics.
The application is so huge, that it is difficult to get into the code base, and the original knowledge is gone for a long.
The code is too fragile so it got expensive to build more value with it.
Old technologies and libraries are not supported anymore.
Unfortunately, it is very expensive to replace an old system that has been built over decades and it does not bring any business value to just rewrite them with new technologies. In the worst case, it never finishes and the old system keeps running forever beside the new application. Did I mention that syncing data between software systems is no fun and expensive as well? And what are we supposed to do in 10 years when the new system will be outdated as well? Do we rewrite it again and have 3 generations of systems running in parallel? Yes that happens, I'm working currently on such a project...
So we are locked in a loop, replacing applications. Actually, we want to add business value and not reinvent the wheel again. What can we do to break this circle? I use an architectural style which is called a self-contained system.
What is actually the problem of large legacy systems?
Before we dig deeper into this architecture, let's see what causes this problem. Why do those systems reach a state where we can't move forward or backward? One of the reasons is the monolithic nature of the architectures which were usually used for those kinds of systems 15 years ago. A common architectural style at that time was the layered architecture. They are cut horizontally into layers like the UI layer, business layer, and data access layer.
We are talking about large applications. Having only horizontal cuts in the system results in a tight coupling between features and modules. That makes it difficult to change things like migrating the UI to a newer technology. And that's just because it's so big. Where should we start? It's like opening the box of Pandora.
What about microservices?
Micro-services are well known to face problems like that. They enable the usage of different technologies, scalability, team decoupling etc. And they are small enough to be easily replaced by a new one when their technologies get outdated.
Are they really a solution? I won't say no. But micro-services get hyped maybe a bit too much. Micro-services are complex to handle. They introduce a lot more complexity into the system. Things like distributed communication, traceability, resilience, monitoring, etc need to be adapted to micro-services. Further, micro-services are not an answer to modularize or split a user interface into maintainable parts. In the end, there is a big danger that it will end in a distributed monolith. We are also talking about UI monoliths.
Between a microservice and a monolith
If we would have a small application we would not talk about it and just refactor or rewrite it. Small applications are easy to understand as a whole. They are small enough to be migrated or even replaced. It also doesn't hurt to throw them away if not needed anymore.
Why don't we break our large system down into several smaller applications? This is it! We can cut our system vertically into completely separated, independent applications. Each application has its own tech stack such as user interface, database, and deployment stack. It has its own backlog and its own release cycle. This way we don't have the overhead of micro-services but each of those applications is small enough to be understood and to be maintained for a very long time.
It is actually a system of systems. This way we can build s sustainable system architecture that is and can stay fit for the future. We don't need to completely rewrite the old legacy system, as well. We can revitalize it by replacing only parts of it, or adding new features with new tiny applications. The coexistence of the legacy application with a replacement is not a risk anymore, but a feature. If we do that, it is important to make sure that the replaced features are built back into the legacy system as well. We make sure it can be slowly transitioned completely into the new self-contained systems architecture.
Let's the main message of this blog post. Large enterprise applications often reach their end of life due to unsupported technologies and lack of knowledge. Rewriting them doesn't bring any value, is expensive, and introduces the risk of never getting rid of the old application. An architecture style called self-contained systems splits a software system vertically into many small applications that are easy to understand and maintain. This way, it's also possible to transition an old, very large software system into a system which is fit for the future.