Speeding up Kotlin Multiplatform

Paul Woitaschek
YAZIO Engineering
Published in
3 min readMay 18, 2022

At YAZIO we are heavily investing into Kotlin Multiplatform and use Kotlin to share all business logic between the iOS and the Android App.
Naturally this also leads to a lot of code. Since we modularize our software properly to achieve encapsulation and fast incremental build times, it also means a lot of Gradle modules. 70 modules and counting, to be more precise.

And for Kotlin Multiplatform, a lot of Gradle modules means a very long Gradle Sync and IDE indexing time. We tried to mitigate some of that by switching to the latest Macbook Pros, which helped quite a bit. But with all the targets we have (1x Android, 3 x iOS, 4 x watchOS), it still takes 6 minutes for Gradle to sync after adding a new Gradle module.

This is a very long time, and worse: It encourages developers to not change any build logic at all and leads to them not adding any more modules.

Is moving these files into their own module really worth the six-minute wait?

Selectively removing targets

The idea here is simple: Fewer targets — less sync time. We rarely need to touch the platform-specific source sets anyway and 99% of the time, we are developing solely in commonMain .
This means that while developing, we can just remove the Apple targets. And it turns out: Apple targets have the most effect on sync times. This is due to the Commonizer, large native distributions and a complicated mechanism that allows you to see what’s in your classpath from within the IDE.

This is pretty simple to implement. First, add a new property to your gradle.properties file:

Now, in your build.gradle.kts file(s), simply check for that property before creating the native targets.

Et voilà — it’s not blazingly fast, but at least we can work with it.

Gradle sync finished in 33 seconds

Bonus: Configuration Cache 🎉

The other big benefit that we can now make use of is Gradles Configuration Cache. With the iOS targets, Kotlin Multiplatform is currently incompatible with the configuration cache. However, without the iOS targets, it’s not.
And this now really speeds things up when building and running tests:

BUILD SUCCESSFUL in 517ms 62 actionable tasks: 62 up-to-date Configuration cache entry reused.

Bonus S01E02: Selecting the Right IDE (hint: It’s Not Android Studio)

As developers, we want to use the latest version of Android Studio. We’re excited about the newly introduced features and sometimes even want to try out the canaries.

But quite frequently, we are hit with bugs, such as Android Studio not being able to resolve classes within the IDE. Kotlin Multiplatform itself is pretty stable, but the IDE experience is far from it.
The answer for us was simply not using Android Studio. Most of the times that we see unresolved classes, a switch to IntelliJ fixes the problem. This also makes sense if you take a look at the internal processes:

Generally, the AGP and AS team are in very close contact with us. Almost all automated tests with multiplatform run only against IJ releases. My personal opinion, as an engineer, not speaking for the Kotlin team, is that Kotlin Multiplatform should be used in IJ over AS. I know that you folks love to use brand new AGP versions, not supported in IJ, but using AS traditionally had more such issues, which is expected considering that tests for MPP are against IJ.

On top of a functional IDE, you also get all the latest updates from Jetbrains long before IntelliJ gets merged into Android Studio. This is especially important for Kotlin Multiplatform, where things are changing and improving rapidly.

Last but not least: We are hiring🎉.
If you love Kotlin Multiplatform and enjoy working remotely in cross-functional teams, we’d love to receive your application!

I’m only needed for the Medium Preview Image :)

--

--