The Denali project.
Hi, I am Naoya, a Senior Engineering Manager at Mercari. Along with my small but mighty team of frontend developers, I am responsible for delivering the Mercari app experience to our customers. Today, I’m here to explain why we’ve made the ambitious decision to completely rewrite our apps using React Native.
Currently, we are experiencing unprecedented growth; GMV growth is 107% YoY, and MAU hit 4.2+ million in December 2020 (YoY +54%). We’re really proud of our 4.8+ average App Store rating, with over 1 million App Store reviews. Our metrics are all looking stronger than ever before. So why rewrite our apps now? And why use React Native? I want to explain how we came to this difficult decision, the challenges it took to get here, why this will be a game-changer for Mercari, and how this is another important step toward realizing our vision to “create value in a global marketplace where anyone can buy & sell.”
With any kind of growth, whether business or otherwise, there are always going to be growing pains — and this is no different for our engineering teams. My team’s headcount has been steady, but growing; we currently have less than a dozen engineers to build & maintain our mobile apps on both major platforms. To date, we’ve taken a hybrid approach to our tech stack. There are native iOS and Android codebases in Swift and Kotlin (with a bit of Java here and there) and we’ve built about one-third of our interface in React Native.
This hybrid app approach with native and React Native layers has pros and cons. When we use React Native, we see higher engineering throughput. With one engineer, we can deploy new features on both iOS and Android with more than 95% code shareability between the two platforms. Developer experience in implementing React Native has been mostly positive, with benefits such as hot-reloading, over-the-air app updates, and use of declarative UI, just to name a few. On the other hand, maintaining hybrid apps has been an ongoing challenge. To work on cross-platform initiatives such as our Design System, we essentially have to implement similar code three times which significantly increases the project’s complexity and scope. Another challenge is data synchronization between the native layer and React Native. As we increase the adoption of React Native in the app, there is more frequent communication required between native and React Native — both in the code itself and between the engineers responsible for it — which adds to the complexity in both domains and requires engineers to understand both tech stacks.
Additionally, since we rarely (i.e. almost never) have equal bandwidth between our iOS and Android engineers, we frequently are only able to develop a product feature for one platform at a time. Then, we have to find time to bring the feature implementation to the other platform at a later date, when time allows. This approach obviously results in feature fragmentation between iOS and Android, which leads to the expensive need for exhaustive documentation from our product and engineering teams to enable us to implement features at a later date. Further complicating the issue, engineers frequently need to jump from one project to another, requiring context switching (which, as we all know, is a tiring productivity-killer), without having sufficient opportunity to iterate on delivered features as needed in response to customer behavior.
As our business continues to quickly grow and we need to iterate faster on our product, we have come to the conclusion that we would need to increase our headcount exponentially to develop our apps using the same methodologies that we’ve been using to date. For those who are familiar with The Mythical Man-Month book, it’s easy to see the communication challenges and productivity concerns that would be introduced by significantly increasing the number of people working on the same projects.
So, we started to look for solutions that could make our current engineering team and future additions to the team more effective–and we didn’t have to look far! In working with React Native over the past few years, we have already seen impressive gains in productivity and the technology has matured significantly. Simultaneously, the frontend team has adopted React to power our web app. When we considered engineering productivity, we saw a possibility to exponentially increase our throughput if we concentrated our frontend tech stack in React (on the web) and React Native (on the app).
From there, we started a technical assessment to evaluate the feasibility of transitioning the apps completely to React Native. We looked at the following criteria:
In regard to quickly shipping & iterating after release, the power of hot-reloading is a clear advantage over iOS/Android compilation time — which takes well over a minute to see the changes of every line you write. Documentation in React Native & Redux Toolkit is well-structured with plenty of code examples. Having a detailed style guide by the framework will also help us understand the best practices. React Native offers sufficient accessibility support and provides APIs to accommodate all users. ESLint for accessibility will allow us to identify accessibility issues. React Native apps typically score highly in testability thanks to the extensive testing library and the highly testable Redux architecture, in addition to the integration testing by Appium or Detox. During a frame rate test for app performance, we achieved 60 FPS on pixel-heavy screens — like search results — and we’re considering implementing the Random Access Modules (RAM) bundle format to improve launch performance. However, we noticed that documentation on React Native is still iOS heavy, especially around performance monitoring. We would like to see improvements to the Android documentation and hope to contribute to this as we increase our understanding of the domain. Finally, code shareability between the two platforms will be extremely valuable for us; as previously mentioned, we’ve already demonstrated that we can achieve more than 95% code shareability between iOS and Android, improving engineering productivity to deploy a feature to both platforms with a single engineer.
It’s not all sunshine and rainbows, though. One potential concern we’ve identified is around crash rates on Android due to React Native adoption. From the hybrid React Native app experience, currently serving 11% of active user engagements in our app, we’ve observed about 1,400 users experiencing crashes from the React Native codebase in a given 7-day timeframe. If we were to increase the React Native presence to 100% with today’s architecture, we estimate that the crash-free rate would go down to 98.91%, which is a major regression from our rate of over 99% with the current Android app. To mitigate this risk, we plan to actively contribute to React Native and create an App Foundation team whose job will be contributing to the issues raised by the React Native framework itself.
Another aspect of the assessment we completed is to engage with other companies that have already adopted React Native, including Chomp and Discord. The information provided by these teams, who already offer rich React Native experiences, provided us with an assurance that apps built entirely using React Native can lead to the productivity gains we’re seeking (see Why Discord is Sticking with React Native for more context).
That all being said, we understand that asking engineers to shift to a different technology is a big ask and it was not an easy discussion to have. One of the major learnings I’ve had during this period is that the decision-making process and being transparent is as important as the decision itself.
While we’ve gone through this exercise, we’ve had extensive discussions at the team level and through 1:1s with members about this decision. There were concerns about the learning curve and, in some cases, this move did not align with individual career goals. To support our team, we’ve put a lot of effort into implementing measures to make the transition as smooth as possible. We started a “React Native class” where we talked about the concepts and designs of React Native and created onboarding documents to help the team learn how to write React Native. We are also preparing a transition period during which native app engineers will have sufficient opportunities to learn about and contribute to our React Native codebase, to build their confidence, to build their confidence over time.
Every strategic decision has trade-offs and we know that there are no silver bullets when choosing a technology, but we believe the pros outweigh the cons and we are excited about the future of Mercari with React Native. With the productivity gains we expect, we can start to form product feature teams (“pods”) with cross-functional team members working together to tackle present and future business challenges. Engineers will continue to have the autonomy and creative freedom to work on solving problems that motivate them. An innovative environment is made possible when we have creative time to work on things; this is only possible when we have more engineering bandwidth than merely trying to keep up with the immediate product development needs. We believe that by fully adopting React Native, we will be on the most efficient and effective path to building the Mercari app that meets our customers’ needs — now and in the future.
Mercari is currently hiring apt folks across all disciplines. Given our particular stack (Go/React/React Native), we’ve always believed in finding capable engineers and teaching them on the job, even if they don’t yet have this particular set of experiences coming into Mercari. In mobile engineering, we’ll continue to have a need for native code and thus plan to hire engineers with a background in native technologies (iOS and Android) who are eager to learn new skills & languages. Stay tuned for future updates about the technology strategy for our new React Native app and more details about our rewrite.