Make the Most Out of Your Next Migration Project

I help product teams build quality software and lead engineering efforts. Currently working at OpenSpace as a Senior Software Engineer.
Search for a command to run...

I help product teams build quality software and lead engineering efforts. Currently working at OpenSpace as a Senior Software Engineer.
No comments yet. Be the first to comment.
Last month I built a regression-testing harness for a single library upgrade โ React Query v4 โ v5 in one of the front-end apps I'm working on. It's about 800 lines of code across four packages. It ru

Images are heavy. When you're building offline support, storing them alongside your application data is tempting โ and eventually painful. I hit this wall building support for image attachments. The n

Deciding how to approach offline support can be challenging, especially once you move beyond the basics. So far, I focused on persisting data that was already fetched as a result of user actions. This

Software engineering is changing faster than most of us can comfortably adapt to. The capabilities of LLM models change almost monthly. New tools appear every week. Advice that felt solid three months

This is the eighth post in my series about offline support in web applications and the fifth focused on the foreground queue. In the previous article, we covered error handling and retry strategies. A

Recently, we've finished a migration of one of the frontend applications I work on from Backbone to React. This was an endeavor for a few months but we've ended up in a much better place, both from the product and engineering perspective. ๐
In this article, I share a few points which have been critical to making this project successful for both engineers and managers. Adopting these strategies can make your next migration project as close to plain sailing as possible.
The process of software development, if done improperly, can be like a black box to product managers or owners. That might be especially true for migration projects which are often almost exclusively technical.
Remember, it's the managers' job to keep track of the progress. That way they can better plan for the future. So unless you create visibility over the migration project for them, there will be questions. A lot of them. That's natural.
Also, remember that if other teams are working on the same codebase, it's easy to get into conflicts on code level or, god forbid, feature level.
Here are a few things you might want to try.
This way your manager sleeps well at night, you get asked fewer questions and other teams can plan their work accordingly, so you don't get in the way of one another.
Before you touch anything, make sure you know the area you're about to migrate. Look for any pieces of documentation available related to that area. Read the tests that you have and validate how much confidence they could give you.
What also helped us in this project was having well-defined tickets. Since there wasn't much documentation, we often went feature by feature, investigating the existing code and transforming the findings into precise acceptance criteria.
One other thing I saw work well also is creating diagrams for more complex flows and logic. Written documentation is good, but visuals are often easier to traverse quickly. They will allow you and your team to understand the logic better, serve as a starting point for a discussion about potential issues and serve as documentation for the engineers to come.
Getting rid of old code can be fun. Make sure, though, you're not only running away from something but running towards something. Knowing when to migrate and how to get it rolling is probably a topic for a separate article - Kent C. Dodds has a great blog post on business and engineering alignment. It's useful to transform the reasons for migration into specific goals.
Here are some of the things we were striving towards.
It's worth thinking about how you're going to roll out your changes long before this happens. This will inevitably influence the entire engineering process.
Most likely you don't want to hit all customers with your big change at once. If your company is using its product internally, roll out your changes there first and let them sit there for a while, monitoring what's happening. If everything's fine, go 1% of customers. Then maybe 5% to 10%, and all the way to 100%, each increment happening after a certain time. At any stage, if something goes wrong you should have an easy way to switch to the previous implementation. This is how you can manage the risk which all migration projects have.
But to be able to consider that, you have to have a process. Here are the two most common options.

Feature flags diagram
Canary releases diagram
We went with feature flags, but there's no right or wrong. It depends on your situation and requirements.
Having this risk management plan will actually slow down the development process. Think about the benefit-to-effort ratio but try to somehow isolate the new version from the old version. That gives you a way to fall back if something goes wrong, which might be more valuable than speed.
The bigger the area you want to migrate, the bigger the complexity.
If we're already doing a full rewrite, why don't we do X, Y, and Z as well.
Seems like a brilliant idea? Well, not really. Migrations already have a lot of complexity to them. With adding new functionality, you need to understand the business context, gather requirements, review designs, think about how to implement and test the solution. Don't spread yourself too thin and limit the number of functional changes.
But what migrations give you is a great opportunity to rethink any abstraction that you might have in the code. Are they useful? Did they speed up the migration process or only made things more complicated? Now is the time to add an abstraction where it's missing or remove a hasty one.
The last thing is technology. For us, the choice was pretty simple. React should be the core, as it is our framework of choice in all other apps. Always choose the tool with an appropriate time horizon in mind. Do your research and don't necessarily go for the new shiny technology. Choose what gives you and your team the highest return on investment given the quality of the tool and the expertise developers on the team have.
I saved perhaps the most important for last. As you see, there are already so many things to keep in mind, we didn't even talk much about making sure that we didn't actually break anything!
That's intentional. You shouldn't have to bother - your tests give you that confidence. Your job here is to evaluate existing tests and decide how much confidence they currently give you and whether that's enough.
For this project, unit tests that existed depended on too many implementation details so we could use them only as documentation. Thankfully, we had a decent suite of end-to-end tests which we could rely on. We also used this migration as an opportunity to write better integration tests for the app, using React Testing Library, and this decision already paid off.
Make sure you have tests to rely on.
I have to say that I really enjoy working on these types of projects. It's a fantastic feeling when things just work and you know that you can remove a ton of old code. Also, along the way we made a few strategic functional improvements that were fully engineering-driven - it was just easier to do things right with a new architecture. And that's a great sign. ๐
To wrap it all up, here are the things to keep in mind.
Ultimately migration can be an excellent learning opportunity. It's worth asking what we can do now so that we don't have to go through another migration in the future. Or at least how you can make the process easier.
I hope it helps you make the most of your next migration project. Good luck!