DEV Community

Jorge Castro
Jorge Castro

Posted on • Edited on

[WIP] The unique journey from .NET mobile (Xamarin) to Kotlin / KMM

This is a work in progress…

…and just like life, change is essential to improve, in my work life, I have taken the decision to transition from .NET as a mobile platform to the remarkable and ever surprising Kotlin ecosystem.

This is my journey of discovery, this is my story, I will make the best out of this so is something worth sharing, hope you enjoy it as much as I'm enjoying it.

How it all started

I have been working most of my career as a .NET Developer, and as of this writing, I have accumulated 14 years of experience to be precise, perhaps not so challenging experience I'd say, but good to be competitive with .NET.

In retrospective, that is a lot, and I have written mostly consumer-facing apps for desktop, web, and mobile platforms most recently, and some server backend apps as well.
Perhaps not a super spiced experience, mostly aligned to everyday coding and applications not too large to face scalability challenges.

But I have always tried to improve upon my previous solutions with an improved on the next time I find similar problems. Not often I write two similar pieces of software with the same code, I always think how things can be improved from what I have done before.

This challenges me to find better ways of coding. Some of those better ways of doing things has led me to learn, for example, the principles in the Pragmatic Programmer book which is a must-read for every developer, and the Reactive and Functional paradigms, still with C# which is object-oriented, but I have tried to squeeze as much as possible out of it.

The Discovery

I found myself in a position where I entered a team where Xamarin native was being used for writing apps. Later on, after some time, I was presented with the current state of the art in native Android development thanks to a colleague.

To my surprise (because I was quite off touch with the pure native ecosystem) a lot has improved and went into, if I can summarize it, into the reactive paradigm, just different flavors of it.

Later also discovered that web development has been all over it and functional programming since React.js was conceived, which also blew my mind, for reference, look at Honeypots's documentary on React.js and go down the rabbit hole a bit.

In any case, a trend I discovered was obvious. In .NET community, Rx and functional programming has been always an afterthought, something few developers, in proportion, ever adopt or put in practice, even though Rx.net was one of the first libraries created to adopt the reactive paradigm, and Java/JS followed after and other platforms.

I always find it challenging, and I believe other reactive practitioners find it too, to introduce this paradigm to other developers in the same .NET ecosystem, it shouldn't be, even today is something you have to deal with.

So, I have been studying how Kotlin's Flow and Coroutines have evolved Rx to levels .NET can only dream of now, .NET folks and leadership have abandoned Rx, and instead we get things like IAsyncEnumerable or INPC that is the same old paradigms plus wrappers of the same old we have had since decades now. As much as I love ReactiveUI for example, it is also wrappers around the same old bindings and commands paradigms.

The Learnings

What follows is just a bunch of learnings I have encountered in this journey, so beware, it may be gibberish and nonsense, but is my evolving understanding of the technologies involved matching with my experience. I don't mind being corrected, even better, just be mindful this is a real-time prediction of things I learn that may change for the most part.

KMP and friends

View Model and State

I have been digging into how KMP or KMM for that matter, shares state and view models to iOS. Considering that Android uses the native Flow and friends to compose UI state, I have found that in iOS you can use Combine framework, which is yet another Rx flavor for Swift.

So, this way in Swift UI you can basically wrap Flows into Publishers and Subscribe to state change, very similar to how you would do it with LiveData, and then you can also "dispose" the subscription and clear the Coroutine scope coming from Kotlin when the view is gone.

I know this and was very easy to identify because I happened to participate in an internal port of LiveData to Xamarin using Rx.net at my job, which turned out to be phenomenal to ditch MVVMCross Bindings and use UDF to manage our state. Hopefully, we would be able to open source it some day, at least for historical purposes, is a good way to document the transition that no one in .NET community has figured out from classic state management to UDF, again born 10+ years ago in React.js, and is still, the way to go.

KotlinConf 2023

I was highly anticipating this conference, and now I could attend my first KotlinConf, this was for me a way to commit to transition from being a .NET Developer to a Kotlin developer if all went well, and it has!

These are some of the insights I gained from attending KotlinConf in April. This is from the perspective of evaluating the technology, and focuses on the aspects that we may be most interested in as .NET developers.

Regarding the future of Kotlin

From the keynote, we can grasp what are the focus areas for the JetBrains team for the development of Kotlin and its sustainable future.

In a nutshell:

  • Expanding the reach of Kotlin Foundation, intended to secure the future development of Kotlin, where many groups are supporting and securing the continuation of its development, including Google, Gradle, Shopify and TouchLab. Also assisting library authors with grants, focusing on expanding multiplatform reach and sustainable development.

  • It shows a clear direction of Kotlin to become the language running on top of every platform, massive focus on Multiplatform, Compose Multiplatform and WebAssembly integration as the driving technologies of Kotlin ecosystem going forward, this creates a better environment to improve tooling for mobile.

  • Focus on tooling for developers, as always has been from JetBrains, and K2 compiler will enable faster and better features and tooling.

  • The stable label to KMP will be added this year, but is production ready and already used by many large organizations, this is to focus on better developer experience.

  • Over 23% of the top 1k Android apps use Jetpack Compose, which is more than double the number from last year. 95% of the top 1k apps use Kotlin.

Essential to watch:

Video: KotlinConf 2023 Keynote

Summary blog post:

KotlinConf 2023: A look at the Opening Keynote

Regarding the present of Kotlin

Kotlin Native is a consolidated multi-platform technology that has been constantly improving since 2018 when it started to mature. Currently, there are many companies who demonstrated Kotlin Multiplatform Mobile (KMM) maturity by implementing their solutions using this tech, many seen at the conference like CashApp, MeetUp, Google (Workspace apps), TouchLab, Xebia and Umain (McDonalds app) sharing their experience working in production with the technology. Some other case studies, including Netflix case, can be found here https://kotlinlang.org/lp/mobile/case-studies/

Probably the most important presentation regarding the adoption of KMM as a platform for mobile dev is the following. And even though there is a lot of information regarding how real-world teams work, we can get a gist of what it takes to put a KMM workflow into production and what to consider for each kind of workflow. This is from the experience of a team helping put projects in production since the conception of KMM:

KotlinConf Video: Kotlin Multiplatform Mobile for Teams

These are the key aspects to consider when adopting Kotlin right now:

  • As a native-first technology, KMM requires expertise in at least one of the target platforms, which is often referred to as a “three-platform tech”. To leverage the technology fully, it is important to have a good understanding of native Android and Compose, as well as a good understanding of iOS and Swift (including SwiftUI) and the Kotlin features that facilitate code sharing across platforms.

  • We have to consider what workflow would work best. Given that the nature of .NET/Xamarin teams in general is that we all contribute to both platforms and shared code, perhaps the Workflow Mode 2 or Shared Architecture approach (as mentioned in the linked talk above) is not limiting as we all would contribute to the Kotlin core library in some capacity. Mode 1 as a Shared Module with an exposed framework could also work with dedicated iOS developers.

  • There are some limitations in tooling subject to improvements, for example considerations in generic interfaces, async cancellation, and enumerations translated to iOS through Obj-C, and tooling to enable more integrated workflows instead of framework based workflows. There are workarounds and community solutions already in use, things will improve with Swift interop and SPM investments this year by JetBrains.

  • While there is an ever-increasing set of libraries targeting KMP as stated in the Keynote (check also https://github.com/terrakok/kmm-awesome), we have to consider there may be some differences with Android libraries, like instead of Retrofit, we may use Ktorfit, instead of Dagger/Hilt we may use Kotlin-inject, and so on, however is built on top of the stability of the KMP approach.

  • The so-called “Reactive Interop” has some natural walls due to the fact we cannot translate asynchronous and concurrent approaches from Kotlin (Coroutines and Flow) to Swift directly (Tasks/Actors/Async and Combine) in the output end or consuming part of these APIs, like UI State where we should consider some wrappers. The hardest mapping setbacks have already been resolved either by community, tooling and broad documentation. In Android, everything in the standard Kotlin works, so no need for a wrapper, but is constantly evolving and is essential to understand how the building blocks work in Kotlin and in Swift and be aware of the new developments as they come. The technology is only going to get more accessible and improve, but not going to solve all problems, we have to still deal with Swift for UI at least.

  • UI sharing through Compose is still in development, but it can be leveraged now in a progressive and optional manner. It's worth considering that this approach may very well be the future of UI, not just in Kotlin, but across other languages as well. The language, approach, and tooling all matter, and it’s clear this ecosystem is fully committed.

  • The approach for KMM is different from other technologies. Optional add-ons building blocks to native-based development, from little code sharing to full UI sharing, Kotlin Multiplatform is designed for this kind of flexibility. It is not an all-in solution like Flutter, Maui or React-Native, we choose what to share, and we can always have the flexibility to fall back to fully native solutions in a much more frictionless fashion with full API availability.

  • The more code we share for iOS like use cases, view models and state management, the less we would encounter Obj-C interop limitations, we can get to an 80/20 shared architecture / not shared + ui code.

Other relevant presentations

This is a curated list around KMM topic from the KotlinConf playlist, great content if you are eager to learn more. Full list here: https://www.youtube.com/playlist?list=PLlFc5cFwUnmwcJ7ZXyMmS70A9QFyUu1HI

Compose Multiplatform for iOS - Great demo of Compose for iOS showing an image gallery with camera and map support! https://github.com/JetBrains/compose-multiplatform/tree/master/examples/imageviewer

Scale McDonald's with KMM - Interesting talk on implementing KMM at scale within a large consumer-facing app for over 60 markets globally!

Meetup with KMM Libraries - KMM at Meetup for Organizers app

Confetti: building a Kotlin Multiplatform conference app in 40min - A fun ride with live coding an app using a GraphQL API and KMM

Kotlin/Multiplatform for iOS developers : state & future - Implementing KMM from the perspective of introducing it to iOS developers and how to make their lives easier, limitations and recommendations of tools and practices

Level up on Kotlin Multiplatform - Nice talk giving a broad overview on libraries and techniques applicable when using KMM

Kotlin Multiplatform Conversions at Android Jetpack Scale - Case study of the experience converting some of the Jetpack libraries to Multiplatform

Kotlin Multiplatform in Google Workspace - How Google is starting to leverage KMP to replace old tooling and share logic in Workspace apps

Arrow Trajectory - This shows how a community project is driven with such a great commitment and focus in this ecosystem. Because Kotlin allows and encourages a great functional development experience, the community has created this project to become the standard to enable better functional programming capabilities to Kotlin. This video shows Arrow history and future.

KotlinConf 2019 Asynchronous Data Streams with Kotlin Flow - This is an old one but was very relevant to me, showing the great investment in elevating the reactive and asynchronous paradigms in Kotlin when they introduced cold streams (Flow) and comparing it to classic Rx, something you don’t see at this level in .NET

Takeaways for the adoption of Kotlin Multiplatform

Based on the facts above and having followed, studied and tried the platform for the latest few months from the perspective of a .NET Developer. I can conclude that Kotlin together with KMM is a proven technology to build cross-platform applications, the key differentiator is the approach as stated above, native first.

Kotlin, as a language and platform, has quickly evolved into a pragmatic, declarative, and expressive language, takes some established practices and elevates them or balances them to integrate into the overall ecosystem very well. From day one, the developers have emphasized and elevated asynchronous, reactive, and functional paradigms in ways that cannot be found in the .NET ecosystem. This is because .NET's efforts are isolated and fragmented, or simply slow to improve due to neglect and lack of leadership, especially for native mobile development. As a .NET developer who has evaluated both approaches, it is a fact that Kotlin and its ecosystem has it all and the risks of adoption are very low.

But it requires time and investment, specially if we aim to rewrite anything, I think the ROI is much higher than the expenses in the long term.

[WIP]

Top comments (0)