When the engineering team at Clipboard Health adopts a new tool, we can’t afford to be afraid of failure.
As a company undergoing rapid growth, we have to run major experiments and take big risks. We can tolerate a lot of potential downside if the upside is keeping up.
Clipboard Health’s growth cuts both ways: we not only have to consider whether a new tool makes sense for the company we are today, but also how that decision will affect the company we want to become.
Growth means we have to adjust how we think about cost and risk. Being too conservative and creating debt are both bigger risks for Clipboard Health than other startups at our stage.
Why Cross-Platform Mobile App Development?
We have to weigh the performance advantages of native development against the added cost and time and coordination between our Android and iOS mobile efforts.
Fully native development is always better once time and coordination cost are factored out, so our relevant questions are:
Is there a cross-platform solution that does everything we need?
Is it possible that the advantages of native development will be too small for our customers to notice or care about them?
If the answer to either of these is “yes,” we wouldn’t proceed.
We believe leveraging cross-platform tools will allow us to attain excellent performance and consistency across platforms while minimizing our mobile development team’s time and coordination costs.
Flutter vs. React Native
We considered two popular tools for cross-app development: Flutter and React Native. React Native uses Javascript under the hood, while Flutter is powered by Dart. Each tool has its advantages.
Performance
Flutter vs React Native
Flutter and React Native share a similar design, and both are quite popular. React Native uses a Javascript-to-Native bridge, which results in a noticeable drop in the frame rate.
Flutter’s Skia rendering engine bypasses this by rendering in-engine and then exercising pixel-by-pixel control over what’s seen on the actual screen of the phone.
React Native is capable of rendering at 60 frames per second (FPS), but requires a significant amount of optimization. Flutter can reach 60 FPS (our goal) out of the box and has overall better performance due to not having to “cross the bridge” like React Native.
We also compared React Native and Flutter against native development for Android and iOS platforms. React Native’s bridge and Flutter’s Skia both result in a performance hit.
For example, in situations where it’s necessary to render complex animations or 3D objects, it makes sense to leverage native frameworks like Core Graphics. Flutter would be a poor choice for building a game.
However, Clipboard Health’s apps don’t and probably won’t ever need that amount of rendering power. We believe Skia will give us more than acceptable performance, without the tradeoff of hardcore optimization in React Native or parallel development of two native applications.
Other Considerations
Beyond just performance, we also considered the developer experience:
Flutter is powered by Dart which is type safe by default; this speeds development by providing IDE assistance (auto-complete) and raising type errors at compile-time rather than runtime
React native is not type safe out of the box, and while it’s possible to add Typescript to the toolchain, this becomes an added step to achieve the developer experience we want
At Clipboard Health, we seek engineers who have a growth mindset, who are looking to improve and acquire new skills, and that have strong opinions about using the best tools and technologies for the job rather than setting constraints to what we already have in place. Additionally, Flutter’s API is comparable enough to ReactJS to make for a shallow learning curve for any frontend engineers familiar with component-based frameworks.
Developer Experience
For these reasons, we chose Flutter.
It doesn’t hurt that Flutter also has a very low barrier to entry, with excellent tooling and documentation readily available.
Running a Flutter project and checking for problems was easy. Flutter’s “Flutter Doctor” functionality is surprisingly robust; it connects directly to the Android/iOS SDKs and identifies configuration errors as consistently as native development environments.
Flutter Doctor also identifies missing plug-ins in various IDEs such as VS Code. Flutter Doctor further saves time by not only identifying problems but also suggesting possible solutions.
Flutter comes with a complete set of built-in components like buttons and drawers, on par with a dedicated component library like Material Design. We chose to build our own design system to maintain consistency across our applications, but the existence of pre-built components with flexible states and multiple variants could be a crucial feature for smaller companies or anyone interested in rapid prototyping.
For state management, we experimented with Provider, Bloc, and GetX and decided that Provider was the best suited for use in Flutter, in large part because Flutter and Provider both use the same “inherited widget” system. The syntax between the two is also very similar: Provider almost feels like a native part of Flutter itself!
We decided against GetX because it adds a lot of dependencies and doesn’t play well with other parts of the Flutter toolset. Many in the industry have considered using Flutter and GetX together to be a bit of an anti-pattern, and this is probably why.
We were also influenced by another library, Bloc. While we decided to use Provider, in large part both it and Flutter are natively supported by Google, we opted to adopt the BLoC (Business Logic Component) design pattern in our application to take advantage of the clean architecture it provides.
Our built-in-house scaffolding solution (which we will write about soon!) works well with Flutter, supports logging and monitoring with DataDog by default, and includes easy-to-use methods to support new API clients. It also includes Firebase Authentication and support for routing. It’s been easy to build testability into every component we’ve built. Overall, it’s a pretty amazing tool.
As good as Flutter is, we expect it to get even better with time. The Flutter community is large and growing crazy fast, with new ideas coming every day. The maintainers have consistently delivered bug fixes and improvements at a breakneck pace, while always maintaining strong backwards compatibility.
The Clipboard Health engineering team will be publishing a series of blog posts to highlight our incredible team, share what we’re accomplishing, and to give a window into our unique work culture. And hey, we're growing! If you're looking to work on meaningful problems that are technically challenging within a super talented team, we'd love to talk to you.