Many medium and large companies operate with legacy systems (old monoliths, rigid local software, or platforms without active maintenance). Although these systems have driven the business for years, they eventually become growth bottlenecks, causing slowness, high maintenance costs, and extreme difficulty in integrating new technologies.
However, the idea of shutting down a central system and turning on a new one causes panic among IT executives. And for good reason: poorly planned migrations result in data loss and revenue disruption.
In this article, we detail how our team at the enterprise systems consultancy executes the modernization of critical software safely, with zero risk of downtime.
1. The Strangler Fig Pattern
Instead of trying to rewrite the entire monolith at once (the classic and dangerous "Big Bang" mistake), the best engineering practice is the Strangler Fig Pattern.
How it works:
- We identify an isolated and peripheral functionality of the legacy system (e.g., the report generation module or notification sending).
- We develop this functionality as a modern and scalable microservice, using efficient technologies like Node.js or Golang.
- We place a traffic router or API Gateway in front of both systems.
- We redirect calls to this specific functionality from the old system to the new microservice.
- We repeat the process for other functionalities until the old system no longer receives requests and can be safely shut down.
2. Incremental Refactoring and Shared Databases
During modernization, the biggest challenge is keeping data synchronized between the new and old platforms while both run in parallel.
Recommended approaches:
- Temporary Shared Database: Both applications read and write to the same relational database (e.g., PostgreSQL), allowing user interfaces to transition seamlessly for the end-user.
- Message-Based Synchronization (Event-Driven): Using RabbitMQ or Apache Kafka to replicate changes in real time between the legacy database and the new database as events occur.
3. Benefits of a Modernized Cloud System
Upon completing the modernization of a legacy system to a decentralized cloud architecture, the operation reaps immediate benefits:
- Elastic Scalability: The ability to automatically scale resources during traffic peaks (Black Friday, monthly closings) without crashing the system.
- Development Agility: Developers can build and deploy new features without fear of breaking unrelated parts of the monolith.
- Cost Reduction (FinOps): On-demand computational resources avoid paying for oversized servers that sit idle overnight.
4. The gateway that diverts one route
The monolith stays on the root path. Only /reports/ goes to the new service. Everything else stays on the legacy app. In Nginx:
upstream legacy {
server 10.0.0.20:8080;
}
server {
listen 80;
server_name app.example.com;
location /reports/ {
proxy_pass http://127.0.0.1:8090;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
location / {
proxy_pass http://legacy;
proxy_set_header Host $host;
}
}
sudo nginx -t && sudo systemctl reload nginx
curl -sS -o /dev/null -w '%{http_code}\n' http://127.0.0.1/reports/
curl -sS -o /dev/null -w '%{http_code}\n' http://127.0.0.1/
nginx -t has to print syntax is ok before the reload. The first curl hits the microservice. The second still hits the monolith. When the old module no longer shows up in the access log, it can be turned off. The queue that copies writes between the two databases is in the n8n and RabbitMQ article.
Conclusion
Modernizing does not necessarily mean throwing everything away and starting from scratch abruptly. Using the correct incremental architecture strategies, it is possible to transform rigid software into a high-tech, scalable, and secure ecosystem, keeping your business running with absolute stability throughout the entire process.