Why we think Flutter will help us scale mobile development at Nubank
An overview of the criteria and study we conducted to decide to use Flutter as our main technology for cross-platform mobile development.
Nubank has been a mobile-first Fintech from the beginning. We started our mobile development with native apps for our Credit Card supporting both Android and iOS platforms back in 2013 and quickly adopted Kotlin and Swift after they were announced. For a while, we supported the Windows Phone platform.
As the company grew (we’re now the largest independent digital bank outside Asia), developing new products beyond Credit Card became a priority and new teams had to figure out how they would ship to our apps.
But how? Well, why not try React native?
Nubank’s third product was NuConta, our digital savings account.
When the NuConta team was staffed in 2016, we were facing a challenge: not enough native mobile specialists available. And it wasn’t easy to hire either, we saw (and still see) fierce competition for these professionals in the job market.
We wanted mobile developers dedicated to the NuConta team because we already knew that specialized teams don’t scale. We believe in autonomous, agile, cross functional teams, working together from Inception to Production, avoiding handoffs and being responsible for the quality, operations and evolution of their products. We believe single teams developing features end-to-end deliver more value, faster.
Writing the same feature twice, only in different languages and platforms, and having to learn all of them, seemed wasteful. Learning one hybrid platform to ship features would reduce the entry barrier for backend developers to contribute to the mobile frontend.
At the time, React Native was an established alternative, backed by some big players. On top of that, our engineering culture is all about continuous learning and improvement (we make it clear it’s everyone’s responsibility to learn and experiment on the job) — so it’s not hard to understand why the NuConta team decided to experiment with this cross-platform technology.
NuConta has reached great success, with more than 13 MM customers, who saved as much as US$ 305 Million in the past 5 years by not paying a series of fees (as of September 2019). They have all used an app developed with React Native + GraphQL, a tech stack very different from the one used by either native platforms.
The story of React Native at Nubank is something we’re very proud of and that deserves its own post.
But today we want to talk about our next step. After all, no matter how successful a tool or platform is, our engineers continue to learn and experiment with new technologies:
A culture of experimenting and learning rapidly
At the beginning of 2019 new product teams, like Business Accounts and Lending, now had a choice to go native or to try React Native.
Around the same time, the industry had already demonstrated great advancements in mobile technologies (just a few announcements from 2019): Kotlin as preferred language for Android, Swift 5 ABI Stability, Flutter 1.0, updates to React Native community governance).
So we found ourselves discussing how to better support our engineers’ productivity when delivering features for our app. Here were some of the issues:
- For engineers who are interested in being more full-stack, the entry barrier was too high. To contribute to the Credit Card one had to learn Kotlin for Android, Swift for iOS and, to help NuConta, one also needed to learn React Native.
- Not to mention the fact that the architecture of each of these options was very different! Our hypothesis is that by reducing the entry barrier for mobile development, Nubank will see more engineers contributing to the codebase.
- Another bottleneck we found when relying on specialized native platform-developers for every new feature or product launch was the “staffing nightmare”, even with our increased hiring efforts there were never enough developers to fully staff our product teams.
We quickly realized that our teams were more important than a technology stack and that having all these choices was causing discomfort and confusion. It was time to seriously investigate which of the cross-platform technologies would be a better fit for Nubank’s needs.
So we set out to charter a task force with the mission to investigate and decide, with buy-in from the whole of software engineering, which technology we should standardize on, considering Kotlin Native, React Native and Flutter as alternatives.
The goal would be to make a choice such that, regardless of the specialization of its members, teams would be autonomous and productive to develop the mobile application and deliver value on a single architecture, programming language and set of conventions.
We assembled a small team with experienced mobile developers at Nubank. They determined 11 criteria to be evaluated in a research project. Here’s a short description of questions of the top 5 priorities:
1.Developer experience: What enables a developer to deliver value and to be productive? Examples: hot reload; component visibility; debugger tooling; IDE integration; and test tooling.
2.Long-term viability: Depicts the level of confidence in the future of the platform. Will the maintainer keep supporting it in the long-term (five years)? What is the likelihood of the community supporting the project if the maintainer decides to drop it?
3.No platform specialization: An engineer should be able to write mobile code for the product without differentiating between Android and iOS. Does the code look and behave the same on Android and iOS, with low occurrence of OS-specific problems?
4.Incremental abstraction cost: The cost of extending the platform for each product task and the friction of centralizing the work on extensions, if required. How hard will be adding a new component? Would we create a dependency on a horizontal platform team?
5.Non-linear abstraction risk: Risk of suddenly requiring large, disproportionate rewrites of our internal abstraction. Would we need to make non-trivial changes across the entire codebase to support a new NuDS (Nubank Design System) component?
We then set out to gather evidence and agree on a subjective score for each of them by using different techniques like:
- testing a Flutter version of one of our features in production
- analyzing communities, repositories, and resources available for each platform
- engaging in conversations with specialists, teams and companies behind the development of the platforms
- implementing a clone of one of our features as a stand alone app in the 3 different platforms
- conducting an internal usability test, were novice and senior engineers made changes to the feature in apps described above
- conducting presentations, debates and team visits to discuss our findings, hear engineers and senior advisors’ opinions, incorporate their feedback and answer their questions
The results of the usability tests were the most interesting. People of all levels and backgrounds (including entry level engineers with no previous experience developing on mobile) participated in a one hour test. They were given a working app, development environment, documentation of the hybrid platform and it’s components and a few, increasingly more complex tasks to code. They were observed by our team while executing the tasks and both answered a questionnaire at the end.
As an example, engineers had to add a feature so users could tap “shortcut” buttons with predetermined values to deposit money into their savings account:
We wrote a report of our research gathering the findings and detailing how we evaluated each criteria. You’ll find a link to request the full report at the end of this article. It was very hard to make a decision, even after gathering a lot of information we had to focus on the 7 most important criteria to come up with the following results:
Drawing from our own experiences (80% of our Android codebase is Kotlin, NuConta is developed in React Native) and evaluating our alternatives against Nubank priorities we feel like Kotlin is a great language to work with. But Kotlin Native is the only platform that doesn’t provide a UI abstraction, making it dependent on native platform tooling for developing and testing. While it scored higher in our lowest priority criteria, not showing limitations of capabilities or risks for app store restrictions, we felt that especially when it came to testing support for expert engineers, Kotlin Native is not ready for us.
We feared a bias towards React Native, so we consciously lowered the priority of another criteria: the cost of building the initial abstraction on the platform, where React Native was a clear winner.
When looking at more important criteria, React Native also wins in community support. We felt no fear of the continuity and evolution of the project and were really happy with the amount of documentation and learning resources available. When it came to breaking changes however, we found that React Native has an order of magnitude more dependencies than the other alternatives, and as such is much more vulnerable to maintenance and upgrading pains.
Our engineering culture strongly encourages test automation, so Flutter shined with its great testing capabilities, that fit nicely with our mindset (built-in testing infrastructure for Unit, Integration and End-to-End tests without the need for rendering to the screen). Whereas React Native requires third-party dependencies, which makes it more prone to breaking changes. We found the Flutter development experience to be superior, with better hot reload capabilities, very strong official documentation, and a more stable API.
After a lot of discussion and contention up to the last minute we decided to use Flutter as Nubank’s main technology for mobile development. This means the new features will be written in Flutter and as the product evolves we expect it to become the greater percentage of our codebase.
We are extremely excited to share this study on the same day we announce a much awaited feature launch: the Rewards program “transfer points” feature was built with Flutter.
Conclusion: what does using Flutter feel like?
So far it’s been great to use Flutter, we expect to have more features built or migrated to Flutter out to our users very soon.
Having to include Flutter in a running app with millions of clients comes with its own set of challenges that we’re gradually overcoming, the first of them being:
- changes in build pipelines,
- creating the main platform channels,
- integrating routing amongst React Native, Flutter, Kotlin and Swift so we can maintain interoperability.
While Flutter is going to be our main technology, native developers are still needed and valued as each platform has its own set of features that require native code (e.g.: native plugins like GPS and camera, Apple Watch, Android minimized apps, etc…) and as the software engineering team at NuBank grows individual specialization is welcomed.
For anyone considering Flutter, we have made our full report with detailed data, pros and cons available for download.
Be warned that what works for Nubank might not work for you. We recommend also looking into what other companies’ experiences were like. While there are companies using Flutter or React Native, Dropbox dropped their multi-platform technology (C++) because of “The (not so) hidden cost of sharing code between iOS and Android” and AirBnB decided on “Sunsetting React Native”.
Oh, and by the way: if you’re interested in working in an environment of continuous learning and experimentation, and excited about developing full stack skills and exploring cross platform technologies for mobile app development like Flutter: we’re hiring.
Thank you André Moreira, Rafael Ferreira, Ana Paula Maia and Paula Rothman for your support with this article.
What's your company's mobile development strategy? Are you using hybrid technologies too? Please comment and let us know what you think of our choice.