Our Journey With Flutter and Dart

Flutter make us focus on what matters most

I’m one of the founders of Tanibox, along with Asep and his wife, Retno. As a board member, my role is generally to give advice and direction. In one point of time, we pivoted our business model and in need of creating an app that works on Android and iOS. I became a little bit involved when we tried to figure out how to do this.

At first, we thought that we just create native app separately for each platform. As we needed to test ideas quickly, we search for a vendor. But after 2 weeks it didn’t work out. The iteration was too slow for us, and we learnt that we really need to build this in-house. The only viable option was React Native. But we disliked the idea of regressing to Javascript.

Flutter is our life saver

I and Asep have written a number of native iOS and Android applications in the past. We agreed that the most expensive investment is in the UI and the interaction as it usually changes quickly, so we want to optimise on this part. We finally hired a seasoned mobile engineer to write our app and challenge him to explore Flutter. This has been working relatively well. This is what we’ve been learning until now:

An agile way of writing UI

The problem with writing the app in two platforms in their own respective UI framework was the time, money, and expertise needed to craft the UI. Every platform has its own behaviours, and every company has its own branding and UI guidelines which may or may not inline with the guidelines set forward by the platform owner. It also takes most of the development time. We’re just a little startup, and we want to test our product FAST.

Flutter architecture

Flutter framework is written on top of Flutter Engine. The engine takes care of abstraction of renderer for three platforms: Android, iOS, and Fuchsia. The framework is focused on UI widget rendering. It implements its own rendering stack based on Skia. It does not use iOS’ UIView or Android’s View class.

Candy Crush Saga vs Angry Bird: Blast

Game engines have been doing this for very long time. Every game engine has their UI rendering library which enables game developer to compose UI with their own branding, style and interaction on all platforms. Games do not even adhere the “UI Guidelines” because they need to stand out.

Applications nowadays tend to design around the brand and not the platform. If people already familiar with the app in one platform, they expect they behave the same in another platform. Brand consistency is important. This is what we want to aim.

Flutter also handles its own animation and gestures. This gives Flutter total freedom on how UI widgets are composed and how the user interacts with them in a similar fashion. Flutter enables us to write our UI based on our brand. The way Flutter was made is a match for our requirements.

It turns out we spent a helluva lot of time building and tweaking the UI before even integrating into the backend. There’s always that “something” that needed to be adjusted fast. Flutter supports hot reload during debug build. Which mean developers can just adjust and run and see the result. This makes us able to iterate the UI for both platforms really quick. On release mode, flutter will spit out the AOT compiled code.

Consistent Way of Communicating With The Backend

Our backend was written in Go, and it exposes RESTful API. To make work effective, we created the SDK to make access to the server endpoints seamless. If we were to implement those in Android and iOS separately, we need to create two different libraries as they do HTTP and JSON marshalling and unmarshalling differently.

Thanks to Dart’s HTTP package, built_value, and built_collection, we’re able to write an asynchronous client SDK with the immutable data structure. This SDK is used by both Android and iOS app and also WebApp because later on, we decided to write our dashboard using Angular Dart to be able to further leverage our shared Dart SDK.

Just recently, the dart team even announced gRPC support for Dart. This is amazing as this will enable better integration as we’re planning to use gRPC on our services in the near future.

A Strongly Typed Language

We have a strong opinion on using statically typed language whenever possible. We like to express something in the term of type. This is the reason we decided not to use React Native in the first place.

Dart is not perfect, but it has things that we need: a statically typed language with the combination of compile-time type checking and runtime time type checking. It has the built-in mechanism for asynchronous using future, and async-await. It helps tremendously in handling the event and network packet.

Dart is similar to Java. Our API SDK for Dart is written by our backend engineer. We don’t really separate engineers by layers and having language like Dart make our backend engineer can create one SDK for all three platforms in the pure Dart. The language is easy to grasp, and it saved us a tremendous amount of time.

But Flutter Also Make Us Suffer

While Flutter saved our investment in time and money. It was also a risk. This tweet showed my frustration when helping the team working on Amazon Cognito.

My frustration with Flutter

Possible Bug in Dart Standard Library

We didn’t use the stable channel at that time because the changes from dart 1 to dart 2 is major, and we do need features from Dart 2. There was one particular bug that bugged me so much is the modpow(x^y mod N) bug on Dart dev channel before version 0.54. Amazon Cognito is utilising SRP and RSA for authenticating and verifying token, and I need BigInt with correct modpow implementation. I scavenged code from other people. Thankfully, Google has Dart code handling simple RSA. I looked at them and learnt that my code was correct, but Dart implementation was buggy.

Documentation Scarcity

When I first used libraries created by Google itself like built_value and built_collections, the docs was nearly zilch. In many occasions I need to peek in the source code on GitHub to know what’s going on and how to use it. Thankfully, Google’s standard of publishing source code has plenty of examples of it.

Need To Build Things Yourself

At the time I wrote the app, there was no Amazon Cognito SDK for dart, so I need to follow their documentation, test them out using raw curl, peek the source code written in other languages and reimplement it in Dart.

We can’t rely on the availability of the libraries written for Dart. Cognito is one example. For me, this is the fun part. But for other people, this can be a no-go. The amount of nights and coffee I spent to figure out how these things work in Dart is paid off as once I can figure them up, it can be used on all three platforms with very minimal changes.

Conclusion

Working with bleeding edge technologies comes with risks but the risk of using Flutter and Dart is worth the investment. The fact that we used the dev channel just make us feel like we are working together with the Google’s Flutter and Dart team by always keeping track of the issues.

We managed to build our first prototype in 3 weeks with single client developer and single backend developer. This is impossible to do if we write them in their own respective IDE and language.

If you wonder what kind of app we’re making, Our CEO will announce it in coming months when our products are ready. So stay tuned.

P.S. This article was published firstly on Didiet Noor’s blog.

Comments on Facebook