Our journey to Kotlin Multiplatform
Introduction
As many of you know Kotlin Multiplatform offers a way to share code between technologies, in this case we will focus on Android and iOS. I will explain why my squad decided to migrate from a separate platform development to share some layers of code (domain and data) and finally go to production.
Initial context
Most of the biggest companies in the technical industry are divided by squads, teams or product areas, our case it’s not different. Each squad has ownership to develop its own products, so we can decide and choose the best technology behind them.
In my squad there is an Android developer and an iOS developer, so it’s usual to start the development of features each one working on his respective platform.
Almost all our features are simple, we are normally just api-painting, performing calls to backend to receive the data and reflect that data on a screen.
This usually works fine until a new feature arrives and compromises it. In this case, this new feature is a bit different, it’s a shopping list. The data that we must to show is introduced by the user and we must synchronize that data with our backend.
This means adding real business logic on the app side!
Well, don’t worry, we are so good and we can keep both platforms align, right?
The problems arrives
As you can imagine all started without problems. But this is a new feature, started from scratch, and a lot of changes in requirements arrived quickly.
The first big difference was the database technology chosen. On Android we started using Room and on iOS Realm, that means to begin with a database relational vs non-relational.
Another big difference was regarding the reactive behavior. On Android we implemented a reactive approach where the list subscribes to the database and each time the database changes the list is updated. On iOS was an imperative approach, on each change on the database they must call again to receive the updated list.
Up until this point I’m sure that you have the same or very similar differences in your features and is not that big, right? For sure your features still works without problems. But, at least in our case, when the synchronization with backend arrives then begins our nightmare:
The synchronization process must be transparent for the user but also we don’t want to overflow our backend doing one call on each change. Therefore we implement a strategy where on each change we add a delay and we send all the changes when the user stops do things. Here another distinction, on Android we use the android WorkManager to solve this but on iOS was totally custom on each screen.
With all that changes, now our database models was different and the synchronization was done at differences moments. Two complete distinct approaches. Our QA team didn’t know how to test it or guarantee which platform was correct, Android? iOS? Both?
If all this is not enough the iOS development started one sprint later than the Android one. Chaos and divergence plus a tight deadline. We thought that maybe can be another way to do all this.
Would it be possible to do things differently?
At this time we thought that we couldn’t continue like that, is a new feature that will evolve a lot and we are wasting a lot of time resolving problems and figuring how to align both platforms.
First solution: copy and paste.
Yes, likes sounds. Seems like the Android solution works better that the iOS approach so the first solution was copy and translate to Swift the domain and data layers.
In parallel we also decide to do a POC (‘Proof of concept’) to check is the current Android solution could be ported to Kotlin Multiplatform (I will probably create another post on this topic).
We arrived at a point where iOS had the exactly same use cases than Android therefore with the POC we only would have to migrate to Kotlin Multiplatform and use them.
The next step was to evolve the POC and generate shared library (lib for Android and a XCFramework for iOS) and add those libs in the respective projects to later replace the current native code implementation on each platform.
KMM and Beyond
The final result was totally success! Now Android and iOS share the same code, same database and same synchronization procedure with backend.
Also now our business logic is only in one place so in case we have to update the logic or fix a bug then we just need to do it once.
Kotlin Multiplatform has been recently put in beta and we are very happy with the results, we want to go even further so we are already working to also share the presenters!
Thanks to that we will sharing the presentation logic, so Android and iOS project will only have to paint the end state that returns our shared library. That means sharing 100% our logic!
Conclusion
Android and iOS are now more align than ever, in our squad instead of have one Android developer and one iOS developer we have two mobile developers.
If your team is similar than ours we recommend you to try it, your team will evolve to the next level and your mobile developers will be more aligned and will work together in a better way to find the best solutions.
Of course you can also try Flutter or React Native, but at least that you have some members in your team that has a deeper knowledge of these platforms, we thought that the normal evolution is to let your Android developer check how easy is KMM.
Is not just feeling, the shopping list is in production since March and we have more than 200k shopping list created and around 600k items added and 0 issues!
Featured in Kotlin Weekly Issue #328