The Journey of React-Native @ Flipkart
Introduction
Flipkart, the largest e-commerce player in India, has over 100 million app downloads and 400 million visits every week. The React-Native journey of these applications started back in 2016.
In this article, we attempt to explain the rationale behind our choice of React-Native, briefly describe the onboarding challenges, and provide insights on some techno-functional aspects. Besides, the article briefly touches upon how Flipkart is currently using React-Native for its application development.
React-Native as a choice
Aside from the core e-commerce shopping funnel, the Flipkart app has many exciting features including videos, social media, and games.
We noticed we had to address the following day-to-day challenges:
- Increased development effort: At Flipkart, the features and designs are uniform by choice, so they behaved the same way across platforms. We built the features/pages on the web stack only once. However, because of stack differences in mobile app development, we had to build every feature separately for Android, iOS. This translated into a significant loss of productivity in the Engineering teams.
- Delayed experiments and bug fixes: The adoption time for newer app versions was very high, especially Android. It was necessary to wait for significant adoption to run AB experiments and roll out critical bug fixes. Such delays can cause negative impact on sales numbers and the customer experience in large-scale sale scenarios such as Flipkart’s most popular sale event, ‘The Big Billion Days’.
To solve these we built Proteus in 2014–2016, a layout parser for Android which enabled us to update layouts over the air (OTA) and to add data bindings on the layouts.
Aside from the solutions for these challenges, we also wanted to equip the layout parser with scripting support to accommodate customisations.
It was then we considered using React-Native which featured the:
- app development for all mobile platforms without significant performance impact
- unrestricted parallel usage of custom native components, as required
- ability to ship JS code over the air (OTA)
These seemed to resolve the challenges, making it our obvious choice for mobile app development.
Working with React-Native
We had many interesting observations and lessons along the way, as we welcomed React-Native into our development forte.
Our React-Native beginning
In June 2016, we began our first-ever migration effort on our search results page, which had an infinite list of heterogeneous items.
When we started, the efficiency in delivering JS updates OTA and improving the performance of the infinite list were our primary concerns. We needed some kind of bundle diffing to push frequent updates.
- We built internal infrastructure to diff JS and enable clients to download patches. We could drop our payloads size by over 90% for our weekly releases. This has become much better today and we’ve moved from ‘module-level diffs’ to ‘binary diffing’ using ‘bsdiff’.
- To solve the infinite list problem, we had to build our own list view, which recycles cells instead of destroying and recreating to save memory and performance. Our first version was backed by native RecyclerView and UICollectionView, and in later revisions we built recyclerlistview in JS (only).
We read the source code and the comments on it, fixed memory leaks, and experimented with the possibilities in the usage of React-Native. Eventually, we saw success in migrating one of the most complex pages with no performance degradation.
Focusing on the correct success metrics
It’s true that optimised native apps can outperform React-Native versions most times. However, considering the benefits such as OTA updates, we came up with the success metric for this experiment.
A lot of teams get into conflicts between Native vs React-Native performance without setting targets. Our intent was to set targets and then see if React-Native can match it. The goal that we agreed internally was to go with React-Native, if we can maintain or do better than existing load time metrics and scroll FPS.
This revision in the thought process and discussion around deciding targets helped the entire team focus on the correct success metrics. After a few iterations, we could achieve the targets and React-Native became an obvious choice.
Meeting Page Load Metric Goals
Every change in the app is profiled to analyse its impact on the core metrics. In our initial experiments with React-Native Android apps, the page load metrics were not as good as Native.
We met the perceived performance metrics with the following changes:
- Reusing the React Instance Managers: We were building them again while switching between stacks. Rebuilding these managers requires a re-parse of JS, leading to slowdowns. You need to create and then cache in memory.
- Making a React instance available before the user loads the page (pre-run it). You can create React context much before the user moves to a react-native page. For more details, click here.
The ‘Home’ page being the first page did not present any chance to pre-run VMs unlike the rest of pages such as search, product, and videos. In instances such as Android App, the launch time was slower in React-Native as compared to the Native by almost 300–500ms (on Snapdragon 625). Therefore, to meet our metric goals, we kept our home page fully native.
With Hermes being launched, we are repeating the same exercise to find out if we can move homepage to React-Native. We understand Hermes reduces the initial cost of parsing JS which helps with an improved launch performance.
Resolving Code-sharing Challenges in Android and iOS
After the initial app launch for Android in 2016, we ran the same code on iOS. Code-sharing wasn’t very successful as some of the abstractions that we built for Android such as the listview was built on Android’s RecyclerView and proved difficult to implement on iOS.
In mid-2017, when we built Flipkart’s Grocery experience on the app, we carefully planned our code structure and native dependencies to avoid code sharing issues. We could share about 95% of the code in this exercise and the development was seamless as the native modules were reliable and reusable. This is when we also wrote the reyclerlistview to ensure a consistent, high-performant, and cross-platform list view (including web).
Generic, carefully planned, code structure and shareable native components/modules across application platforms, solved for our day-to-day challenge on ‘Increased Development Effort’ and its proportional productivity loss.
Using OTA Updates for Quicker A/B Testing
Flipkart has an AB platform to try out multiple variations of layouts, capabilities, or overall UI. Often, we run tests and experiments to understand what’s best for customers and accordingly ship updates.
With the classic problem of delayed update adoption among mobile app users, it took about three months for our app to reach a 90% adoption. With native, for small and medium experiments we needed at least 6 weeks to close the AB experiments.
In React-Native, we can push minor changes and experiments OTA instantly, which positively affects the overall data volume available to test on. We can either speed up ABs or do many more ABs. Now, we close the A/B experiments in about 3 weeks, ensuring that we present the right experiences at the right time for the user. Our differential downloader also ensures that we do not overwhelm users with too much JS download.
Getting Mobile Web Code-base Ready for React-Native-Web
When we moved our mobile site to React-Native-Web we had to first trim down the React-Native-Web library and replace some components with our versions, considering the size and performance requirements of the website.
In addition, we designed our mobile web integration such that the web could inject its own version of native modules / components so that our React-Native code doesn’t have to understand the web platform.
Once dependencies were implemented in mobile web code, our existing React-Native pages were imported just like any other component and assigned routes on our mobile web code base.
As much as code-base readiness for React-Native-Web took its time, the experience has been seamless thereafter. Most of the mobile website today runs on React-Native-Web.
React-Native @Flipkart in 2020
Our tech stack
- It is a combination of Native, React-Native and React-Native-Web.
- Most components are on React Native, while the Home page is on Native.
- Navigation in our Apps is on Native to support easier switching between different stacks (react-native, native, web view)..
Our team structure
- Teams have Web, Android, and iOS engineers with both Native and React-Native knowledge, working on app development for multiple functions. This ensures everyone takes decisions together, covering solutions across stacks.
- All repositories are open to contribution from any team.
Our multi-widget framework
We use an in-house multi-widget framework which allows us to control page layouts from the server side.
- Different distinct or related widgets come together to form different pages.
- Page Layouts for these pages are powered by backend services.
- Multiwidget abstracts React-Native and React-Native-Web complexities to a large extent.
- Development process is as simple as adding new widgets in a lot of cases.
Deployments
- Separate deployments for Native and React-Native apps with separate repositories, too.
- The diffing mechanism generates update patches instead of the full bundles, ensuring that we do not overuse data from the consumer point of view.
- The app does not wait for a relaunch or explicitly ask the users to press a button. Updates seamlessly happen in the same session.
React-Native and Cross-Platform — A few lessons
- You need to design the cross-platform components and native dependencies considering the perspectives of all platforms. If not thought through early, you may end up fixing behaviour inconsistencies every time you build something new.
- We strongly believe that the fundamentals of most platforms are similar. However, the individual platform level nuances require time to understand and are best handled by platform experts.
- Typescript worked well for us while managing our large code-base. Our native developers learning React-Native also found it easier to transition to.
- When we moved our mobile site to React-Native-Web, we realised our code structure wasn’t best suited for lazy loads, as it was designed for the native apps. Despite our efforts, we’re still not happy with the numbers. We’re improving here by adding server-side rendering to optimise first loads while we restructure some code.
- It is our opinion that solving some aspects such as lazy loading JS on the web might have been easier without our cross-platform requirements.
Way Forward
Flipkart uses React-Native for building apps across Android, iOS, mWeb. We have structured our team and code to ensure high output and reuse. As a team, we are passionate developers working on a highly rated, fast, and responsive app.
As we continue investing our customer-centric development efforts in React Native and giving back to the community, we’ll keep you posted on our progress in this space.
We are always looking for React, Frontend & Backend devs. Checkout the latest openings on our jobs portal.