Files
plans/articles/2026-02_KMP-en.md
Михаил Капелько d4028d2a0d some
2026-04-03 10:19:38 +03:00

122 lines
5.9 KiB
Markdown

TODO-Title: Does LinkedIn publication have a title?
TODO-URL: LinkedIn
TODO: Вернуть хостинг своего сайта на GitHub?
TODO: Починить открытие видеозаписей
TODO: Сделать ссылку на Русскую статью из Английской
TODO: Сделать ссылку из Английской статьи на Русскую
Is Kotlin Multiplatform able to cut development costs for products
that support multiple platforms? My calculations say yes, by 21%.
# Current state of products for multiple platforms
One of the most popular ways to develop for multiple platforms relies on having
a separate team for each platform. For example, here's one particular bug I faced
in the russian messenger MAX some time ago:
<iframe src="https://kornerr.ru/vid/max-msg-disappear_2026-01-28.mp4"></iframe>
As you can see, while I was chatting with GigaChat AI my messages were
disappearing: Android had the bug once (the 4th second), Web had
the bug multiple times. Having a different behavior on multiple platforms means
there are different teams doing the same product for multiple platforms. Each
team has its own programming language, its own architecture, its own code review
process, its own set of unique bugs, its own team of testers, its own wage fund,
and so on.
Thus, the more we duplicate the code, the more we have to duplicate the
organization structures. Kotlin Multiplatform (KMP) can help reduce code
duplication. Of course, KMP won't remove code duplication completely, only
to some degree. Let's have a look at my hobby project GitBudget to find out
that degree.
# GitBudget summary
GitBudget is a tiny hobby project to help me ease calculating my day-to-day
spendings. Currently there's no history, no Git support, etc. Nonetheless
I've been using it for several months now to speed up tedious calculations of
the two important figures:
1. Overrun: Did I spend more than my daily budget allows? If so, how many rubles?
2. Left ₽/day: How many more rubles do I have left to spend a day by taking the overrun into account?
I don't intend to dive deep into the formulas, it's outside the topic of the article.
If you're interested you can have a look at the source code here
[at GitHub](https://github.com/kornerr/git-budget).
Let's see how the application looks like for Android and iOS:
![Android, iOS](https://habrastorage.org/webt/e2/bz/f5/e2bzf5lblg0xsydakc88zb5a_hu.jpeg)
No fancy UI/UX here, each UI element is a standard one (sometimes not even
aligned correctly). As a user I usually use the application the following way:
1. Paste from the clipboard the sum I spent yesterday (Spent)
2. Paste from the clipboard the remaining budget balance I had for yesterday's morning (Morning balance)
3. Copy the result of calculations into the clipboard (Result)
# Development costs
Let's divide the source code by three groups;
| № | Group | Example | Android files | iOS files |
| --- | --- | --- | --- | --- |
| 1 | UI | Jetpack Compose, SwiftUI | MainActivity.kt, VM.kt | AppView.swift, VM.swift |
| 2 | Platform | ClipboardManager, UIPasteboard | budget.kt, main.kt, other-android.kt, registerOneliners.kt | budget.swift, cld-ios.swift, other-ios.swift |
| 3 | Logic | budgetShouldResetMorningBalance | budgetFun.kt, entities.yml | budgetFun.kt, entities.yml |
I use KMP only for logic in GitBudget. UI and platform code are native. Why?
Because logic is under my full control, it's only updated when I need it.
UI and platform, on the other hand, are the properties of Apple and Google.
They dictate the rules and update UI with the platform to their liking
(for instance, Apple's unavoidable [Liquid Glass](https://www.nngroup.com/articles/liquid-glass/)).
We'll have a look at two objective indicators: lines of code and time spent to
implement a functionality.
## Indicator #1: Lines of code
| № | OS | Total | UI | Platform | Logic |
| --- | --- | --- | --- | --- | --- |
| 1 | Android | 692 | 160 (23%) | 221 (32%) | 311 (45%) |
| 2 | iOS | 540 | 90 (16%) | 139 (26%) | 311 (58%) |
**Conclusion-1**: I didn't write 311 lines of code for iOS **again** thanks to KMP, that's **58%** of all iOS code
**Conclusion-2**: From the perspective of both operating systems (692 + 540 = 1232), these 311 unwritten iOS lines of code result in **25%** of code I didn't write for the whole project
## Indicator #2: Time spent to implement a functionality
I've recorded the process of adding a new `Paste` button for `Morning balance` input both for Android:
<iframe src="https://kornerr.ru/vid/git-budget-balance-android_800_2026-01-28.mp4"></iframe>
And iOS:
<iframe src="https://kornerr.ru/vid/git-budget-balance-ios_800_2026-01-28.mp4"></iframe>
The results are:
| № | OS | Implementation type | Description | Time |
| --- | --- | --- | --- | --- |
| 1 | Android | Initial | I've created a new functionality that has not existed before | 17:34 |
| 2 | iOS | Secondary | I've used already existing logic in KMP, only added a new UI | 07:33 (43%) |
**Conclusion-3**: It took **57%** less time to repeat the functionality for iOS, i.e., it happened **2 times faster**
**Conclusion-4**: If we assume that creating the same functionality for both OSes without KMP would take 17:34 * 2 = 35 minutes, then the saved 10 minutes to repeat the functionality for iOS result in **21% of saved time** for the whole project
# Conclusions
Thus, these are the figures when using KMP:
1. iOS lines of code down by **58%**
2. Total project's lines of code down by **25%**
3. Time spent to repeat the functionality for iOS down by **57%**
4. Total time spent to implement the functionality for the project as a whole down by **21%** (this is the figure I've used in the beginning of the article)
# Questions to a reader
1. Is 21% of saved time worth it?
2. Is 21% good enough to actually step into KMP realm yourself?
3. How important is it to synchronously release the same functionality for both OSes?