How we validated Flutter at scale for funda
At funda, we're constantly validating how new technology can add value for our users. Flutter is one technology which we believe will help us attain parity in design and implementation. Rajat Anantharam, Platform Engineer Mobile at funda, explains how we went about validating Flutter as a solution fit for feature teams to build features simultaneously on web and mobile apps.
Funda is the #1 online real estate platform in the Netherlands, with our consumers at the heart of our business decisions. Our goal is to provide a seamless user experience for buyers and sellers alike, across all devices, on every part of their customer journey. To achieve such a goal, we must devise platform-agnostic solutions with the consumer at the heart of the value proposition. In this blog, I detail how we went about validating Flutter as a solution fit for feature teams to build features simultaneously on web and mobile apps.
Over a period of three months, we went about validating the following questions:
- How does a Flutter module integrate with the existing mobile apps?
- How do we integrate multiple Flutter modules with the existing mobile apps?
- How do the modules communicate with the native apps?
- How do we test performance of a flutter module at scale?
How does a Flutter module integrate with the existing mobile apps?
Description
If multiple feature teams within the organization would like to build features for the mobile apps, what would such a process look like? We considered four feature teams building four features simultaneously. How could they go about integrating the features they are building on the mobile apps? We assumed here that the features are built with Flutter.
Solution direction
We looked at existing solutions within funda and devised a strategy based on our learnings. They are as follows:
- Every feature is a Flutter module
- The feature is owned by the feature teams. More on team ownership can be found here (bounded contexts)
- A feature should have adequate test coverage, testing the business logic of the feature
- A feature can be integrated on the apps if and only if:
a. It is built on the CI
b. All unit/UI tests have been passed
c. A binary can be built which works on the latest Android CPU architectures.
d. An artifact is published on Azure Artifacts - The mobile apps will only update to the latest version of the published artifact prior to release
Key findings
✅ DART has a low learning curve
✅ Flutter has an active community of open-source contributors
✅ Straightforward to integrate with existing iOS and Android app
❌ Increase in app size
See also: The funda hacka-talk with 3 engineers
How do we integrate multiple Flutter modules with the existing mobile apps?
Description
In this task we investigated what it means to have multiple modules integrated in the mobile apps. A module in this case is a Flutter module which is launched with a specific route. For the validation step we took two independent Flutter modules as examples. One was a Flutter module for searching realtors on our platform, and the other was a Flutter module for local insights. So there were two independent modules, with their own independent implementations. We further implemented a way to launch the two modules from the mobile apps.
Solution direction
Currently it is only possible to integrate a maximum of 1 Flutter module to an existing iOS & Android app. Hence we implemented a workaround with an umbrella app as documented here: https://github.com/flutter/flutter/issues/39707
- Implemented an umbrella app, which is the only module that the iOS and Android app will integrate.
- Created a parent/child relation with the umbrella app as the parent of all the child modules
- Integrated the umbrella app module to the apps and created entry points for each module
- Initiated the modules with specific routes.
Findings
✅ It is possible to integrate multiple modules despite the limitation from Flutter, thanks to the workaround.
✅ Integration with the apps is quite straightforward.
❌ A single module leads to an increase in build & deploy time of the umbrella app (increases linearly with every new module).
❌ There is a linear increase in the size of the apps. More modules = Bigger app.
❌ Though this is not an immediate problem, the non-modular nature hinders scalability.
❌ Versioning will become hard with multiple modules that have a single umbrella interface.
How do modules communicate with the native apps?
Description
In this task we looked at how Flutter modules can communicate with native apps. We covered the following important use cases:
- Being able to track analytics from a Flutter module.
- Being able to pass logged-in user information to a module, e.g. (logged in/email/userid etc.)
- Being able to pass privacy consent information to the modules, e.g. (cookie preferences/personalisation preferences etc.)
Solution direction
Flutter provides platform channels as a way of communicating between modules (Dart) and native apps (swift & kotlin). Here's the architectural overview of platform channels:
Since platform channels by default are not typesafe, we used Pigeon. See: https://flutter.dev/docs/development/platform-integration/platform-channels#pigeon.
Findings
✅ The implementation with Pigeon makes everything typesafe. Further, we chose to implement a schema module which defines the contracts between modules and native apps. This makes the entire implementation non-breaking.
✅ Pigeon has a steep learning curve. Not very clear documentation for our architecture.
✅ Pigeon generates code in Dart, Java and Objective-C. The iOS and Android apps like to stay away from new Java code and new Objective-C code.
See also: Machine learning: the model behind funda's Waardecheck
How do we test the performance of a Flutter module at scale?
Description
To use Flutter for building features on mobile apps, the user experience must remain unaffected. To validate Flutter as a good solution fit for building real-world features, we agreed upon the following guidelines:
- Re-building a key component on the mobile apps with Flutter.
- Choosing a component in the apps that is used heavily by the users.
- Choosing a component in the apps that is heavy on rendering.
- Choosing a component that is of high business value.
Solution direction - We decided to rebuild the photo viewer on the mobile apps with flutter. It met all the above requirements for validation.
- We monitored the performance of the view (at scale) using firebase performance monitoring https://firebase.google.com/docs/perf-mon
- We set a baseline for crashes and compared it after shipping the flutter module using firebase-crashlytics https://firebase.google.com/docs/crashlytics
- We ran the experiment for a month across
Findings
✅ 100% crash-free experience for users who experienced the media viewer built with Flutter on Android, tested across 17K users.
✅ 100% crash-free experience for users who experienced the media viewer built with Flutter on iOS, tested across 16K users.
Conclusion
Flutter is an excellent cross-platform tool that can accelerate feature development on mobile apps. It is built to perform at scale, has a low learning curve and a great online community of software engineers.