A few weeks ago I was trying my best to investigate the plausibility of what Kotlin Multiplatform Mobile could be. We’ve heard the promises of “write once everywhere” before but they have always been limited in flexibility and in my opinion, never actually “felt” native in the end. We’ve had experience working with Xamarin, React Native, and Flutter and I’m sure anyone involved with those projects would be a strong advocate for continuing to work in any of those frameworks going forward. Perhaps that comes down to the specific implementations, but to get features unique to platforms you end up writing a bunch of platform specific code anyway. At the end of the day you are finding yourself saying… “if only I had done this native, this would be so much easier.”
Yet, the more I’ve heard about KMM the more I’ve been excited about the possibility. Largely because of what it is not trying to do. It’s not trying to recreate how the view system works on either platform, it’s not trying to turn your website in a single web-view, it’s focusing itself on the business logic for your app and because of this, I think this has the potential to become a very a powerful tool.
So, I started playing around with a very simple idea. Basically the simplest app I could think of. What if I could pull down my current weather forecast from the internet. Seemed easy enough, but I quickly learned that some of the dependencies I’m used to were not going to work in the KMM. No matter. There are already a decent number of libraries available written specifically to be compatible with KMM. So I was on my way, and pulling down data and displaying it came together pretty quickly. But where we quickly launched into problems was with ViewModels.
Gray Areas #
What can be considered “business logic” and what is considered “state” or “view state” can be pretty subjective. After reading a bunch of different blogs, I thought it would be neat to have an event based system that each platform would be able to observe and change the state appropriately. This quickly became annoying having to use special libraries to convert things like LiveData
and ViewModel
into a platform agnostic versions of themselves, and although it was do-able constantly felt like I was shooting myself in the foot. The more I thought about how to handle this by moving logic farther up, the less it felt like it made sense to have in my shared code. I ultimately started thinking that the best thing to have shared would be my data layer. Packaging up all of my API communication and models into a single package they could both use is appealing, but I then learned the downside of coroutines
in iOS.
Asynchronous Annoyance #
Up until this point, I felt like everything could be relatively handleable by due diligence of a team, working together and defining lines on what to share and what not to share. But working with suspend fun
in iOS proved to be the feature that made me start to question how helpful any of this actually was.
One of the basic things I wrote initially was a function to pull down the weather.
suspend fun getWeatherForecast(): Forecast {
return api.getWeatherForecast()
}
Pretty simple. Calling this in Android was as simple as creating a scope to launch it in.
viewModelScope.launch {
repository.getWeatherForecast()
}
However, when it is crossing over into Swift you lose all of the understanding of what a coroutine is. You are left with something like
repository.getWeatherForecast { data, error in
if let forecast = data {
// do something with the forecast
}
if let actualError = error {
// do something with the error
}
}
Although, I don’t love writing that every-time, writing a thin wrapper around all of the API functions to make it look nicer or to convert into async/await
wouldn’t be the end of the world. But, as far as I can tell, you had no real way of informing the coroutine to stop running. This may not be a game changer, but does seem like it could result in some interesting issues down the line.
Ultimately, I’m not fully out on KMM, though I will say that the use case where it would be successful is probably limited, at least as a first attempt. Hopefully with time, we can look back at it again and see what improvements have been made. A future where I am only writing business logic tests once is a good one.
Looking for more like this?
Sign up for our monthly newsletter to receive helpful articles, case studies, and stories from our team.
To RFP or not to RFP?
January 19, 2024Selecting the right digital product partner is not just about ticking boxes in a request for proposal (RFP). It’s more important to engage in a meaningful discovery process to find a collaborator who can turn your vision into a successful digital reality. Here are three things to watch out for as you search for the perfect digital collaborator.
Read moreProduct Strategy
November 22, 2022A look at Product Strategy at MichiganLabs. Why we do it, what it is, what it is not, and how we approach it.
Read moreThree principles for creating user-friendly products
January 25, 2023Grayson discusses three guiding principles he utilizes when designing user experiences for products.
Read more