We’re sure refactoring and migrations are a challenging topic, which is why we ‘saved’ it for last. Every project has its challenges, every infrastructure has its own ways of being.
In today’s episode, concluding the series of #frontendatbytex, Codrin is here to make the case that nothing is impossible, and even horror scenarios have a silver lining.
Below is the entire script of the video. If we’ve got you hooked, you can always binge watch our entire series here.
Codrin: ‘Hi, I’m Codrin and I’m going to walk you through the process of refactoring and migrations.
There are lots of crazy scary things about it, and we’re going to start with those, so please just bear with me – it gets better. Imagine this scenario, as taken from a horror movie. You have a project that has gotten really mature, one that started two-three years ago. Engineers came and left. You have tasks and improvements that take more than two weeks to complete, and even more time if you want to develop new pages or features. Your entire development team is busy all the time with these tasks or other client facing bugs. This prevents them from focusing on the real problem, while they’re patching and patching the existing code and hoping for the best. All this apparently unbreakable cycle does is delay the unavoidable.
It’s not even about the codebase size, the problem you are facing is adding new features on top of what is considered legacy. When you develop new functionalities your product starts behaving unpredictably, and you get a lot of regression bugs. The quality assurance team needs more and more time to thoroughly test the entire functionality while in the development phase. Most likely your existing application is using a framework or a set of libraries that were stable at the moment development started, which has since become outdated. Aside from the issues that derive directly from outdated technologies, it’s also becoming harder and harder to find developers to work with your existing tools.
The industry has moved forward at a fast pace, and your old libraries are now a security liability. All of the security patches are available, but on their latest version, which is also introducing breaking changes that you can’t deal with at this moment. Your project manager is also having a hard time delivering the new features or bug fixes for the production environment on time. This is because the development branch has code that is not production ready. Now you’ve got frustrated customers to deal with on top of everything. Over the years the design team added or even updated the visuals, and your application now lacks consistency. This has a huge impact on your clients, and the support team has to put in the extra effort to show them how to use specific old features. The entire core of your application, the one you started with, is the one that looks outdated. This is the code that nobody worked on, for the past year. Although it’s the main component of your application, nobody really has an in-depth understanding of it because most of the original developers have already moved on to other products or companies. You have some brave engineers who try to fix bugs here and there, but they end up adding more in the process. All they do at this point is put out fires, only to create bigger ones that are harder to keep up with.
But enough ‘horror’. Let’s focus on how you can go around and fix some of the problems. Ideally, clients have been giving feedback and the design team already prepared new mockups on how they envision the next version of the product. Everything looks clean, and the entire design team is now eager to see their dream come to life. So how do you get from one point to another? Well, you can start by planning in advance. This means a lot of meetings, in which business analysts, designers and technical architects will have to decide what to focus on the next version of your product. This is essential, since feedback is crucial to the design team to iterate upon. While the end mockups might look different from the ones you began with, you now have a good starting point that has most of the corner cases covered. You have to consider old features, new ones and how you will scale the application while staying consistent on the visuals and behaviors.
If you don’t have designs, then start from the center of your application and build upon this as a base. While the design team is working on the new version, in parallel, you can start a ‘strike’ team to work on a framework of components. You should search for solutions that solve isolated concerns like: forms, tables, state management and so on. Document your findings and how you are planning to use this technology stack. We should learn from our mistakes, so gather all of the non-functional requirements from your legacy application. Try to set some objectives that this new framework aims to perform better at. Organize your team so that you have two groups that work well together, either on new features or on maintaining the current product. Don’t make them exclusive, and always assign them in pairs to work on a feature: one from the ‘strike’ team that develops and one from the ‘maintaining’ group, with a consulting role.
Weekly sessions of show and tell will give the software development cycle an agile feel. Speaking of agile, you have to iterate fast, and be flexible with every problem that appears. Code reviews and merging things as soon as they are almost complete will ensure that these components are battle tested before using them in production. From a User Interface architecture standpoint, there is no better time to upgrade your enterprise product. Today, you have a nice range of tools and patterns that can help you migrate your legacy application to a better, component based architecture. You will need a bridge of communication between your legacy framework and your new one. This is temporary, so once all pages and features are ported over it can be deprecated and even deleted. Pages that have been refactored, can live in a different repository, or you can create a monorepo using module federation, the latest webpack feature. A micro-frontend solution can be developed to enclose your legacy application in the new one. This enables your old architecture to use modules from new one to enhance existing pages. This will add behavioral consistency throughout your application.
Now it’s a good time to involve the maintenance team to drive the shape of the framework, by gathering feedback and organizing it in feature requests for the strike team. Preparing for the next component, in advance, with interfaces and use cases will maintain a constant velocity of delivered features. Quick tip: speaking of delivering, if a page has a good amount of bugs, maybe writing it using the new framework is a better option than fixing them. Once you have a way to glue everything together, do it! Test how the new application works and, once it’s stable, make the switch. Congratulations! The hard part is now over.
In time, all of the other pages will get their rewrite, and be ported from one space to another, from the legacy package to the migrated one. All of your developers will get familiar with the newly inhouse-framework, making the migration process easier because most of the work is already cut out.