Legacy migrations: You will fail (and that’s fine)
Rebuilding a legacy platform from scratch is really fun. Sometimes you need to replicate a lot of business logic placed somewhere inside a really big monolith full of unreadable hacks, massive functions, or lacking any sort of tests. Sometimes it even shares responsibilities with stored procedures in different databases with restricted access, or no one is able to tell you a single thing about them.
Under these circumstances, let me tell you a little secret: you will fail. There is no way a team is able to understand all that complexity, as well as rebuild the whole thing in a sensible amount of time. So you’ve got two options:
- Focus on building the perfect system that never fails
- Focus on building a system that fails perfectly
I typically prefer to go for option number 2. Working with legacy system rebuilds makes you trust very few things, as so many things can go wrong. So replacing a legacy system is all about managing risk—here are a few tips:
Managing your data and resilience in migrations
One of the first challenges when replacing legacy systems is dealing with data and resilience. Without a proper strategy, any failure can have lasting consequences.
Backup your data
I’m not only talking about backing up your databases here. Especially if you’re the source of truth, make sure you back up your data in different, cheap storage like Azure Blob Storage or Amazon S3. Not only in case of server failure, but also in case your data model gets corrupted along the way.
Use a data bus for resilience
Introducing a data bus adds an essential safety net. Among its main advantages:
- It helps to decouple your services
- It offloads requests
- It improves and eases recovery and retries
- It makes error handling easier
- It helps to avoid bottlenecks
Ensuring control and visibility
Rebuilding a system without visibility is like flying blind. You need mechanisms to maintain control and ensure stability.
Replay your events
As I said, you will get it wrong. If your input data comes from people operating other systems like an external CRM or CMS you don’t want to ask them to resave 1000 items for you, three times a day just because your team needs to reprocess data from last week. Save it in your platform and build the ability to replay this data to have more control internally.
Build a cockpit
Would you jump onto a plane that is flown without any sort of environmental feedback? Make sure you build an operational cockpit to be able to fly your software with guarantees: monitors displaying operational metrics, proactive alerts and a good logging system are some of the aspects you will need to consider on every platform you build.
Keeping the team accountable and aligned
Beyond technology, migrations succeed when the team is close to the problem and accountable for the outcomes.
To understand how concepts like agile, delivery and DevOps play together, we probably need to understand first what is the value of a software team. Its main value is to solve real business problems, often done by delivering working software into a running production environment frequently and in a sustainable way.
To achieve this, developers need to stay very close to the problem:
- Talk directly to stakeholders to avoid misunderstandings.
- Work collaboratively with the product owner to ensure priorities are aligned.
- Operate, release, rollback and monitor the software they build, taking ownership of the lifecycle.
This increases accountability and reduces communication burdens (which usually bring delays).
Preparing for external dependencies and bottlenecks
No matter how solid your platform is, third parties and performance constraints can undermine it. Preparing for these risks is essential.
Do not trust 3rd parties. Ever.
“This old system never failed in 10 years”. This is what I heard from a customer when we started a rebuild of their legacy platform. Well, guess what? It did fail.
Always make sure you assess the old systems you will depend on, and take into account technical constraints like rate limits, payload sizes…
Also consider how to process data when these systems fail, because they might: it could be a token revoked without previous communication, it could be a 500 error, it could be a memory leak, or it could be an API contract no longer respected. Plan for failure.
Figure out where your bottlenecks are
When you’re building a new platform (especially if it needs to integrate with third parties), always run performance tests engaging these external systems before going live. In which areas will your platform suffer when scaling capacity? Focus on making that area stronger, or it will bite you sooner or later.
In one of the legacy migrations we recently implemented, we noticed the old system would take 6 seconds to digest data. Because we ran performance tests on time, we could change the architecture design, offloading that process to happen in the background so users wouldn’t be affected by this legacy constraint.
Conclusion: planning for failure, building for resilience
Hopefully, these tips will be valuable to you! What other learnings from your experience can you add?
Legacy migrations will always involve uncertainty. The goal is not to avoid failure but to plan for it—through backups, resilience, visibility, accountability, and foresight.
At Orbitant, we know migrations are not just technical challenges: they are opportunities to strengthen systems while protecting business continuity. That is why we help organizations design architectures that are reliable, adaptable, and resilient, turning inevitable failures into moments of learning and improvement.