In this series, I talk about my experience with sharing code with Kotlin Multiplatform.
- Part I. Introduction
- Part II. Library development (In progress…)
- Part III. Depending on native library (In progress…)
- Part IV. First successful application (In progress…)
In part one, I talk about why I have decided to give Kotlin Multiplatform a try.
Cross-platform mobile team
I have worked as an Android developer for nine years now. Most of the time, I worked in platform-specific teams. I found that a platform-specific setup is a right way to go in cases where your team has to deal with complex intricacies of the underlying system. Or in cases where you cannot provide the same product across the operating systems. Android has always allowed us to do a bit more than we could do on iOS.
However, I have also worked on products where we were fulfilling almost identical requirements as on iOS. When we talked, we often discovered that we solved the same problems. And not only that. We would often find out that we approached them in a very similar fashion.
Native mobile, Android and iOS, are almost identical under the UI. They are architecturally homogenous.1
And just by that, we laid out the groundwork for tighter collaboration between our two platforms. The potential was in reducing repetitive work that was needed to keep our products in sync. Product managers, designers and other stakeholders have to sync with both teams. And the nature of two teams working on identical requirements is that the implementation will differ. And just as ripples in water, differences in time will only grow. Maintaining two solutions for the same problem is not ideal.
Also, there was no incentive for us to work together. Collaboration with the other side was minimal. So we all just created our platform-specific versions of licensing, analytics, remote config, etc.
One way to fix it is to mix up teams and create a cross-platform mobile team. It will solve the need to sync twice with the stakeholders. Ideally, it would also encourage more collaboration between iOS and Android developers. However, this is not what I have observed.
The problem is that we both work with different codebases.
First, the pace of development will be different. Eventually, Android and iOS will be at a different stage. Not able to talk about the same thing again.
Next, we didn’t solve the problem with multiple solutions for a single job.
If only we could share code and work on the same codebase :)
It has always been a bit of a taboo in the industry. The main reason is probably all the failed attempts at this.
Some of it has definitely to do with what Kevin Galligan always says:
Shared UI is a history of pain and failure. Shared logic is the history of computers.1
Which almost always ends with a worse UI/UX experience for the user. Worse performance. And lack of support or tooling also means a worse experience for the developer. This topic deserves a separate article.
Another important detail of these solutions is that neither Android nor iOS developers are familiar with language and environment. But on that a bit later.
Let’s focus now on sharing logic.
There is one solution that has proven to work, and actually, a lot of Android and iOS apps use it. It is to share C++ native libraries. We use established solutions for graphics, encryption, networking and many more.
I even worked on a project that used a C++ library to share the main functionality. It was for cloud-based file sharing. We used the same library for both Android and iOS. But we did not develop it or contribute to it. Which I think is a crucial point to make here.
Even though it solves the issue with duplicate implementations, for Android and iOS developers, it was a black box. So, you require an extra team that would handle that library. And it creates unnecessary dependencies outside the team.
A problematic dependency introduces significant delays and/or are too unpredictability and/or increased work in progress (WIP) for the dependent team, slowing them down considerably.2
The solution would be for Android and iOS developers to learn C++ and contribute to the codebase. But almost no iOS or Android developer wants to go that way.
I think the main reason is that nobody wants to step outside their comfort zone. Especially not to the land of low-level languages like C++.
There is an article from Dropbox about their experience with sharing C++ code on mobile3. I highly recommend going through it.
By writing code in a non-standard fashion, we took on overhead that we would have not had to worry about had we stayed with the widely used platform defaults. This overhead ended up being more expensive than just writing the code twice.3
Although they concluded that the overhead of sharing code outweighs the benefits, I think that the main problem was sharing C++ code.
Not that developing a C++ library is inherently wrong, but it is way different from what we are used to in our day-to-day work on both platforms.
And here is where Kotlin Multiplatform (KMP) comes in.
With Kotlin Multiplatform, you can share code written in Kotlin on multiple platforms.
- It produces code that is native to that platform.
- You can also access the platform native code.
- You can still work with any native library you are using.
That already improves the situation by at least making one party happy. The Android developers. We have been developing in Kotlin for several years now. We are also familiar with the libraries and concepts used in the Kotlin world (e.g. Flow, Coroutines). So for Android developers, creating this shared code is not that different from Android-specific code.
That is already a win over-sharing C++ code in mobile products. Some iOS devs that I discussed this with were OK with this setup. Android devs would write and maintain the shared code (as they would write it anyway).
However, I also think that with KMP, there is a higher chance that iOS devs would be willing (and able) to contribute to the shared Kotlin code.
- Kotlin is a high-level language, very similar to Swift.
- Flows5 provide asynchronous streams of data like Combine6.
- And with async/await7, Swift has structured concurrency very similar to Coroutines8.
I hope now you see why I am excited about KMP. Next time, I will talk about my first attempt at development with KMP.