Adopting a modern tech stack is essential for any organization embracing the digital transformation journey. The modernization of web applications is a core requirement as customers demand high performing and well-designed user interfaces. These tips are directed to teams migrating to React but can be applied to other modernization processes as well.
In our experience, React is the most desired front end JavaScript framework for enterprises. Unlike many other frameworks, React is focused on a specific goal – view rendering – leaving software architects the flexibility to finely tailor the rest of the ecosystem. For the experienced software architects, this sense of freedom means avoiding vendor lock-in by relying on the language – JavaScript – rather than a framework’s mindset.
Our clients have migrated to React for a few reasons:
- Their legacy app didn’t have the capabilities to support modern browser features and rich user interfaces.
- Domain knowledge of the applications went away when their developers departed their organization, causing a significant loss of know-how. You should never be in this position.
- Feature bloat, technical debt, and dependencies of libraries and frameworks that are difficult to maintain cause their application to embark on a trend of ever-increasing costs and time to develop new features and perform maintenance. In this scenario, regression issues are more likely to occur. This, of course, affects the company’s ability to capture new revenue (new features = new value to the market) and hurts the company’s bottom line (wasted time = wasted money).
Based on the experience, I collected 21 best practices for migrating your digital products to React JS. These best practices helped Modus Create migrate numerous projects across many industries and varying application complexities.
All of our clients reported:
- Improvements in conversion rates
- Reduced time and cost to deliver new features and bug fixes
- Developer team experience and satisfaction went up because they could focus their energies on creating rather than fighting the legacy stack
The following React migration best practices are helpful to product managers, developers, user experience designers, quality assurance engineers, and DevOps engineers.
Best Practices for a Successful Migration to React
- Invest in your strategy; create a goal alignment with the team(s). Business goals, product goals, tech goals, and team goals should be identified and shared. Being able to clearly share the WHYs that influence strategy is important to everyone on the team. Good leadership will create a sense of ownership.
- Invest in your team; train the team early in the process. A new tech stack brings novelty. “Build one to throw away” shouldn’t refer to your flagship product. Invest in a week-long training, and even better, let the team build a prototype of the most important feature.
- Audit the legacy application. A detailed assessment will help reveal the reasons for existing pain points. It will also help set clear goals for this modernization journey. 3rd party technical assessments can be extremely valuable as they can uncover previously unknowns and create assumptions about your legacy stack that help suss out truths hidden deep in the underlying architectures.
- Select the right partner. You should look not only for the right skillset and experience migrating to React, but also for partners who are experts in agile methodologies, project management, DevOps, quality assurance, and customer experience. Allow yourself time to vet and review references. Also, make sure the partner cultivates a good company culture.
- Agree on the migration progression strategy. You can go bottom-up or top-down. If you choose to go with the bottom-up strategy then find components with the least number of dependencies to start from. Know that there will be a performance penalty until the migration is completed caused by multiple simultaneous frameworks, routing parallelism, etc. The top-down approach, also known as the Strangler pattern, lets you select a sub-app or a meaningful section of the legacy application you can deploy in full. For example, cart functionality is a meaningful section in a webshop. Either approach should allow you to start deploying early and receive feedback while you iterate through the rest of the migration process. React is a strong option for either of the approaches: top-down or bottom-up. The key is in incrementing progression consistently.
- Start small and simple. Your team needs to score wins early to start getting comfortable with the new stack. The stakeholders will also be able to see the benefits early.
- Treat React migration as digital transformation. It’s an opportunity to improve parts other than just the front end. One of our clients committed to migration to React using the legacy backend APIs that were meant for POSs in their retail stores. Some of the business goals were impossible to meet until we migrated some of the APIs to microservices.
- Invest in Open Source. Chances are you will be using a lot of Open Source projects that are self-funded, such as React Router, Webpack, Babel, and others. Recurring donations, even if small, help keep projects maintained for your benefit. At Modus Create we continuously support amazing initiatives like React Router, Webpack, VueJS, etc.
- Extract the critical know-how. Over the years the team has probably identified and fixed important bugs that you don’t want to repeat after the migration. If it’s difficult to create acceptance tests, document that knowledge for manual quality assurance testing.
- Automate early. Code standards and formatting, accessibility rules, and performance budgets can all be automated before writing the first line of code. Some checks like lint and auto formatting are great candidates for staged files in the pre-commit phase. The others are best implemented in a Continuous Integration environment. React’s developer experience ecosystem is full of amazing libraries and products.
- Split work into small chunks. Minor code increments allow faster reviews and quick fixes. You can always use feature branches and feature deployments, but increments should be small. On some projects, we even establish git hooks that warn developers when the amount of changes they introduce is over 1000 lines. Short PRs create a sense of transparency and get merged a lot quicker.
- Create an onboarding process for new team members. Chances are the team will grow or experience some turnover. You could also be introducing people on a temporary basis to provide important know-how to meet feature parity with the legacy app. Good documentation will improve productivity and pave the way for a more efficient onboarding. Kitchen sink implementation with Storybook, testing deployments, useful NPM scripts and even a well-containerized development ecosystem with Docker will be a lot of help.
- Maintain a lasting Strangler facade. As soon as you start deploying new code, chances are that the users will be accessing old functionality on a new platform. For example, they might be accessing an old URL. You might need a translation layer in place that ties legacy and modern applications together. In many cases, this layer could exist in the cloud as redirects or services like serverless compute. Good examples are AWS Lambda or Cloudflare Workers. Serverless on the Edge or CDN is a great choice as it comes with extremely low latency of around 30ms worldwide.
- Bring in the tests. Even legacy tests can help identify issues or help bring edge cases to the team’s attention. Chances are good that you’ll have to migrate the tests with code, but that doesn’t mean you should create tests from scratch.
- Don’t go back to rewrite the early migrated code. Many teams fall victim to going back to rewrite parts of code they migrated early. Of course, we’ve learned a lot and are embarrassed by our level of thinking from several months ago. However, rewrites are hard to justify compared to fixing bugs or creating new features. Don’t confuse this with technical debt, which is intentionally crippled technical capability done in favor of productivity. There should be a business reason for everything, especially committing to a rewrite.
- Maintain good documentation. Outline everything you’ve learned. List the reasons for every decision. Write down all the todos. Good documentation will help with the longevity of your product and avoid future rewrites. At the very minimum, use JSDoc-style comments. For better results, sprinkle them with TypeScript-friendly annotations that enhance Intellisense features in IDEs like VS Code. Modus Labs teams maintain Markdown documentation for Open Source Projects, whereas our Atlassian professionals like to set up a more versatile documentation management platform like Confluence for enterprise React migrations and digital transformation projects.
- Identify key users. Usually, there are internal and external users of the app. When the team understands personas and usage contexts, they can understand the legacy app better and easily make just-in-time decisions for the benefit of the modernization.
- Set healthy performance budgets. Performance is directly correlated with conversion rates. React is easy to learn, but it does require expert attention to set up a great performing architecture. One of our clients reported a 24% higher bounce rate due to their newly migrated Dashboard taking 10 seconds to load. Within a few days, we made changes that dropped loading time to under 3 seconds, effectively slashing bounce rates in half and improving conversion rates by as much as 30%. Consider managing performance metrics via open-source budgeting tools like Modus Gimbal. Gimbal shows how every commit affects performance and warns if changes degrade user experience beyond thresholds.
- Ensure access to customer feedback. As soon as the first bit of migrated code is in production, ensure the team gains access to relevant customer feedback. They need to be able to understand the issues your customers are facing to fix them quickly.
- Use a Design System. Design System is a library of components and design styles published as code, created to ensure consistent and scalable adoption. No matter how big or small the project is, design systems help with maintenance and create a great layer for decoupling business logic from views. Invision Design System Manager is our favorite tool for maintaining design systems, and it’s compatible with React and Storybook. One of our clients used the design system in their proprietary CMS where content administrators managed views and pages. It’s good to create that kind of separation of component vs business logic development. Components are in React’s DNA.
- Compare before and after. This is like eating the desert after preparing a grand meal. While this step feeds our egos, it can also show areas where the legacy app performed better than the new modernized application.
Don’t forget that migrations take time and cost money. In our experience, 100% of our clients in the last 9 years have reported better conversion rates after completed migrations. That means that investment in migration produces a significant return.
Treat migration as a digital transformation and prepare accordingly. The process is best performed when iterations are made quick, easy, and highly agile to allow for early customer feedback. Automate as much as you can in order to reduce friction, enforce standardization, and improve productivity. Transparency is the key to a successful React JS migration.
Grgur Grisogono
Related Posts
-
Ext JS to React: Migration to Open Source
Worried about Migrating from Ext JS? Modus has the Answers Idera’s acquisition of Sencha has…
-
Ext JS to React: FAQ
This is part of the Ext JS to React blog series. React is Facebook's breakout…