This post originally appeared on the Jetbrains blog
GitLive uses Kotlin Multiplatform to share code between IDE plugins (for all JetBrains IDEs and VSCode), as well as soon-to-be-released mobile applications for iOS and Android.
A team of 5 working on the project have written over 12k lines of Kotlin code as a shared library used by 4 different platforms: Android, iOS, JVM and Node.JS. This shared library represents 75-85% of the total code written for each platform (the other 15-25% being platform specific, mostly UI code).
As a result:
- Time to market is reduced because there’s less code and fewer bugs, and because code maintenance is simplified.
- The same consistent functionality can be provided on different platforms.
London-based GitLive is an instant messaging and code collaboration platform built specifically to help developers streamline technical discussions. Nicholas Bransby-Williams founded the company in 2019 to solve a fundamental problem facing distributed development teams: communication.
Adding a real-time layer to the transactional nature of Git, GitLive allows teams to seamlessly discuss, review, share, and even edit code together, live, from within their favorite code editor.
Offsetting the tendency among developers to work in isolation, GitLive encourages communication through the Team View, where teammates can see each other’s work in progress and receive notifications of potential merge conflicts in real-time. The GitLive plugin is available for all major code editors, including VSCode, IntelliJ, PHPStorm, PyCharm, and Android Studio.
The developers at GitLive have extensive experience with mobile application development. They learned that sharing business logic across platforms brings worthwhile benefits, but they also found it hard to force developers to write everything in a single language. GitLive chose Kotlin Multiplatform over other multiplatform technologies for its wide range of supported platforms and advanced interoperability with native code.
GitLive started development in 2018 with Kotlin 1.2, focusing on the plugin for JetBrains IDEs (JVM). Next came the VSCode extension (Node.JS). Kotlin Multiplatform was still experimental at the time, but this did not pose an issue for the team due to the maturity of Kotlin/JVM and Kotlin/JS.
Development of the Android application did not begin until the release of Kotlin 1.3, and most recently development of the iOS application started with the release of Kotlin 1.4. This worked out well for the team, as by the release of 1.4, Kotlin/Native had matured.
Despite the development for each platform being staggered, the goal from the very beginning was to share as much of the code as possible between all four platforms.
Sharing the code
When it comes to multiplatform development, there are two camps of developers. The first camp advocates a “one language to rule them all” approach. Kotlin enables this approach, and it is possible to write everything in Kotlin from end to end if you wish. The other camp endorses implementing the common logic as a library and then consuming that library in the platform-native programming language. Kotlin covers this scenario as well by providing good interoperability with other languages.
GitLive opted to develop a shared core library in Kotlin that would be consumed in the native language for each platform. The team put extra effort into ensuring that functionality which makes sense on multiple platforms was implemented as shared code.
“The ability to build a shared core where we can leverage the power of coroutines in a single language that runs on two completely different platforms has saved us an immense amount of time when developing the product.“
In fact they split their shared business logic into three libraries – core, containing code relevant to all platforms, code-ide, for IDE-specific code (running on JVM and JS) and code-app for code specific to mobile apps (running on Android and iOS).
The shared libraries represent 75-85% of the total code written for each platform. The remaining 15-25% is UI code for the respective platform, which connects the shared core and the platform libraries (IntelliJ Platform SDK, VSCode API, Android and iOS SDKs). As a result of their years of experience developing mobile apps, the developers felt it was important to give customers the best experience by building native UIs specific for each platform (instead of using WebViews, for example).
For communicating with the Firebase backend, they also developed a multiplatform library, firebase-kotlin-sdk, which is hosted on Github.
Writing an API that could be consumed from several different languages and completely different platforms is challenging. The developers had to carefully study the requirements of the client code to ensure that the API of the shared library is easy to consume.
Consuming a Kotlin-based library from TypeScript was a bit challenging in the beginning. There were a few things the team had to implement themselves, as they were early adopters. For instance, the definition files (d.ts) had to be handwritten.
To ensure that the client developers have a straightforward API to consume on their respective platforms, the developers of the shared core designed it to expose the types that you expect in your client language.
They convert the types used inside the core SDK to the relative types used on the API surface of JS platform just before passing the values to the client. An example would be List (in Kotlin), which is converted to an array when passed to JS. Another example is Pair, which the team uses in Kotlin. But in JS, tuples are simply two-element arrays. So the team converts the pairs to two-element arrays before passing these values to JS client code.
“For us, it is important to find good developers. And good developers want to program in the languages that they know and love. iOS devs want to code in Swift, while VSCode extension developers want TypeScript. It is also important to them to use the types that are idiomatic to the language. The ability to make this possible with Kotlin was an important aspect of our project.”
Asynchronous programming is hard, but it’s been made easier in recent years with the introduction of async/await in languages like C#, and reactive programming frameworks such as ReactiveX. It feels like Kotlin’s coroutines took the best parts of these developments in asynchronous programming and iterated them further to create an extremely powerful library.
“Harnessing the power of Kotlin coroutines, especially being able to practise reactive programming across all platforms with Kotlin Flows, has been a game changer”
Being able to leverage this power across multiple platforms was a huge deal for us. Business logic can be written a lot more concisely using an asynchronous, reactive framework like coroutines, which saves us an immense amount of time when developing the product.
GitLive developers liked the ability to use Kotlin to share code between different platforms, which resulted in less code, fewer bugs, and simplified code maintenance. Speeding up development and maintaining a consistent user experience were some of the key benefits gained from adopting Kotlin as a development language. This was possible thanks to the asynchronous programming support offered by Kotlin Coroutines and the language’s multiplatform ability.