The journey with our client, a leading player in the world of fitness applications, started at the bustling RNEU 2022 Conference. The primary goal was to accelerate the development of a groundbreaking set of features that would impact the experience of individual users, giving them more value than ever before. The path ahead had some unique challenges. One of them was no previous experience on our client’s side working with an external agency and the fact that their in-house application had complex legacy features and a large existing user base.
With much work ahead and time ticking away, our partner was determined to accelerate its development. Our primary challenge was quickly understanding and assimilating their in-house knowledge and domain expertise accumulated over the years. As the project peaked, we committed to a team of three seasoned developers who rotated through multiple epics. Our team's main task was to work on the front-end of new sets of features for creating unique experiences for premium users.
Examples of features implemented by our teams were:
This intense collaboration lasted for ten months. With much more to come in the future!
As the client’s in-house team expanded, the project became more complex to navigate. To address this evolving dynamic. We bought a Product Manager on board to facilitate cooperation between our external team and the client’s internal group.
At the beginning of the project, we had some challenges not to operate as separate entities. In the end - both of our companies had slightly different operational styles. However, we ultimately became a cohesive, high-performing team with a shared objective through mindset shifts, breaking down boundaries, and embracing unity.
We had some great successes along the way. A significant success came early in our collaboration. Within the first week, our developer grasped the system's complexity and contributed to feature development. This quick integration showcased our team's adaptability and technical expertise, adding value to the project and setting a precedent for high performance in the following months. Then, our team demonstrated agility by delivering ten significant features in a rapidly changing environment. Despite finalizing designs and requirements for each feature shortly before completing the previous one, we maintained continuity and made constant progress.
A notable moment was identifying the origin of significant performance issues that negatively impacted user reviews. At first sight, the problems were connected with implementing new features. However, during our investigation, it came out that there are three interconnected reasons.
Moreover, there were two very unique technical challenges our team faced, which are important to consider while working on a legacy product:
Despite its established user base, the fitness app was grappling with legacy code, a common issue for long standing applications. The app was built using class components and Redux was employed in the older fashion with containers rather than hooks. The implications of this coding approach were significant. Maintaining and extending the codebase demanded extensive time and resources. It also made onboarding new developers to the project more challenging due to the code's complexity and lack of familiarity with the old style of Redux. It was clear that we needed a modern solution to overcome these technical and business challenges.
We revamped the project structure to improve the development process. This reengineering enabled developers to create and maintain the app more efficiently, minimizing downtime and increasing productivity.
The beauty of hooks lies in their simplicity. They allow us to write cleaner, more concise, and more maintainable code. By converting the legacy class components to functional ones using hooks, we made the code easier to understand and maintain. From a business perspective, this meant reduced development time, lower maintenance costs, and improved scalability.
Similar to React, we utilized hooks in Redux to simplify state management within the app. The hooks like `useSelector` and `useDispatch` allowed us to cut down on boilerplate code, improve readability, and make the components more portable. From a business standpoint, this approach accelerated feature implementation, improved code quality, and enhanced collaboration between developers.
The modernization of a legacy codebase isn't a switch you flip. It's a process. As we joined the project, we began the refactoring work by converting code using old approaches to new, more efficient ones. This not only made the code more transparent but also significantly reduced its volume by eliminating many unnecessary files - effectively improving how fast the application works in the development environment, which saves time as people do not need to wait that long for something to load. As a result, the repository became much cleaner and easier to navigate.
The whole process started with establishing a set of guidelines to streamline the process:
The impact of our approach was visible almost immediately. Our developers were able to implement new features within the first weeks of engagement.
Additionally, the newly written code proved easier to navigate for incoming developers, many of whom had not used the 'old' approach before. This meant that the onboarding time for new developers was significantly reduced. Later on, it was battle tested, when a new developer joining the team could start delivering value in the first weeks of his engagement in the project.
Notably, only a portion of the application has been refactored so far as our focus needed to be on creating new features. Yet, the portions that have been updated have already yielded significant benefits, and established a benchmark for future development.
The application was running on an older version of React Native that started causing performance challenges over time. The most significant issue was a slow initial screen render, negatively impacting user experience and overall app reliability. To address this, we explored the latest versions of React Native in hopes of resolving these ongoing issues.
The straightforward solution seemed to be an upgrade to the latest React Native version (0.71.2 at the time). And that was exactly what we did.
However, during the updating process, we stumbled upon a significant issue with overall app performance and memory consumption in the newest version. As it came out it is a problem that many others faced in developer communities such as this one: https://github.com/facebook/react-native/issues/36123#issuecomment-1553108712. This directly threatened the application's stability post-update, adding a layer of complexity to our upgrade plan, and forcing us to act quickly.
Given these potential stability issues, we decided on a strategic downgrade. We revised our initial plan with the company's CTO and downgraded the React Native to the second latest, stable version. While the newest version may have had additional updates, opting for the slightly older version was a strategic decision based on compatibility and stability considerations.
This enabled us to resolve issues mentioned previously, while still improving from the initial state.
This journey highlighted the importance of flexibility and adaptability during software upgrades. Each version of a framework or language comes with its own set of challenges and benefits, and understanding these is crucial in determining the best course of action. This experience further solidified our belief that a measured and flexible approach is essential for software updates, particularly in complex, established applications with many dependencies and nuances beneath its hood.
Our firsthand experience with various versions of React Native and the challenges they present enables us to provide robust and tailored solutions for our clients. We are fully prepared to assist you in navigating the ever-changing landscape of app development, ensuring optimal performance and user experience for your product.
Our successful collaboration on this project is a testament to the power of seamless communication, mutual respect, and shared goals. Together, we navigated the intricate labyrinth of the project, consistently delivering results that met our expectations. We eagerly look forward to more collaborations that push the envelope of innovation and drive digital transformation.
Whether you represent an established enterprise or a blossoming startup, we stand ready to aid you in navigating your tech journey. We can help you fight and resolve technical debt, manage rapid development cycles, and create innovative solutions that make a difference.
For those of you who are faced with similar challenge, we want to provide detailed information on factors to consider when deciding on a version downgrade and offer best practices for a smooth downgrade process. This will help developers navigate the complexities of React Native updates and ensure a successful downgrade.