May 26, 2018

1322 words 7 mins read

Our Journey With Flutter and Dart

Our Journey With Flutter and Dart

Flutter allows us to focus on what matters most

image

Flutter applications showcase

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

At first, we thought that we would just create a native app separately for each platform. After 2 weeks it didn’t work out. The iteration was too slow for us, and we learned that we really need to build this in-house. The only viable option was to use 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 well. This is what we’ve been learning up to now:

An agile way of writing UI

The problem with writing an app on two platforms in their own respective UI framework was the time, money, and expertise needed to craft each. Every platform has its own behaviours and every company has its own branding and UI guidelines which may or may not be 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.

image

Flutter Architecture

The Flutter framework is written on top of Flutter Engine. The engine takes care of the abstraction of the 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.

image

Candy Crush Saga vs Angry Bird: Blast

Game engines have been doing this for a very long time. Every game engine has their UI rendering library which enables the game developer to compose UI with their own branding, style, and interaction on all platforms. Games do not even adhere to 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 it to behave the same in another platform. Brand consistency is important. This is what we want to aim for.

Flutter also handles its own animation and gestures. This gives Flutter total freedom on how UI widgets are composed and how a 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 to the backend. There’s always that “something” that needed to be adjusted fast. Flutter supports hot reload during debug building. 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 Communication With The Backend

Our backend was written in Go and it exposes a RESTful API. To make it work effectively, we created the SDK to access to the server endpoints seamlessly. If we were to implement those in Android and iOS separately, we would 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 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 Statically Typed Language

We have a strong opinion on using statically typed language whenever possible. We like to express something in terms of its 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 a built-in mechanism for asynchronous using future and async-await. It helps tremendously in handling 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 a language like Dart enables our backend engineer can create one SDK for all three platforms in 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.

image

My frustation with Flutter

Possible Bug in Dart Standard Library

Edit: This is already Fixed. 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 irritated 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 the 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 learned that my code was correct, but Dart implementation was buggy.

Documentation Scarcity

Edit: This is improving, but still lacks. When I first used libraries create by Google itself like built_value and built_collections, the docs was nearly zilch. On many occasions, I needed 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 in it.

Need To Build Things Yourself

At the time I wrote the app, there was no Amazon Cognito SDK for Dart, so I needed to follow their documentation, test them out using rawcurl, 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 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 Google’s Flutter and Dart team and always keeping track of the issues.

We managed to build our first prototype in 3 weeks with a single client developer and a 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 the coming months when our products is ready. So stay tuned.