Stop Writing the Same Code Twice: Sharing Business Logic with Kotlin Multiplatform
Sharing business logic between Android and iOS applications using Kotlin Multiplatform (KMP).

Stop Writing the Same Code Twice: Sharing Business Logic with Kotlin Multiplatform

Advertisement

Here is a blog post written specifically for My Core Pick.


Stop Writing the Same Code Twice: Sharing Business Logic with Kotlin Multiplatform

Raise your hand if youโ€™ve ever fixed a bug on the Android version of your app, only to realize three weeks later that the same bug is still terrorizing your iOS users.

We have all been there.

It is the classic mobile development struggle. You have two codebases. You have two teams (or one very tired freelancer). You have two languages.

But you have only one product.

For years, the industry solution to this was "Hybrid" frameworks. We tried PhoneGap. We wrestled with React Native. We flirted with Flutter.

While those tools are great, they often ask you to compromise on the User Interface (UI). You have to rebuild the look and feel from scratch in their ecosystem.

But what if you want to keep your native UI? What if you love SwiftUI and Jetpack Compose?

What if you only want to share the "brains" of the app, not the face?

Enter Kotlin Multiplatform (KMP).

Here at My Core Pick, we believe in working smarter, not harder. Today, Iโ€™m going to show you why KMP is the future of sharing business logic and how it stops you from repeating yourself.

The "Dual-Platform" Trap

The "Dual-Platform" Trap

Letโ€™s talk about the problem before we dive into the solution.

When you build a native app for iOS and Android, you aren't just writing the UI twice.

You are writing everything twice.

You write the networking layer in Swift and Kotlin.

You write the database logic in CoreData and Room.

You write the data validation logic (is this email valid?) in two different files.

This is the definition of redundancy.

It isn't just about the time it takes to write the code initially. The real pain comes later.

It comes during maintenance.

If you change a business rule on Android, you must remember to change it on iOS. If you don't, your app behaves inconsistently.

Users notice this. They might not know why, but the app feels "off."

This duplication increases the surface area for bugs. It doubles your testing requirements. It doubles your cognitive load.

There has to be a better way to handle the logic layer.

What Exactly is Kotlin Multiplatform?

What Exactly is Kotlin Multiplatform?

Kotlin Multiplatform is not a framework in the traditional sense.

It isnโ€™t a "write once, run anywhere" black box that renders a canvas on your screen.

KMP is an SDK designed to share code between platforms.

It compiles Kotlin code into JVM bytecode for Android. That is the easy part.

But the magic is that it compiles the same Kotlin code into LLVM bytecode for iOS. This means it runs natively on Apple hardware.

To Xcode, your shared Kotlin code just looks like an Objective-C framework.

You can import it, call functions, and read data just like you would with any other native library.

The philosophy here is simple: Shared logic, Native UI.

You keep your beautiful SwiftUI views. You keep your performant Jetpack Compose layouts.

You just stop writing the code that powers them twice.

What Should You Actually Share?

What Should You Actually Share?

When I started with KMP, I tried to share everything.

That was a mistake.

The power of KMP comes from knowing where to draw the line. You shouldn't try to share your buttons, animations, or navigation transitions.

You should share the Business Logic.

So, what does that look like in practice? Here are the three main pillars we focus on.

1. The Data Layer

This is the low-hanging fruit.

Every app needs to talk to the internet. Every app needs to parse JSON.

In a traditional setup, you have Codable structs in Swift and Data Classes in Kotlin. If the backend changes, you have to update both.

With KMP, you write your data models once.

You use a library like Ktor for networking and Kotlin Serialization for parsing.

You write a repository class that fetches the data, parses it, and handles errors.

Both your iOS and Android apps simply call repository.getData(). They don't care how the data gets there. They just display it.

2. Local Storage

Database management is complex.

Managing migrations on two different platforms is a nightmare.

With KMP, we use libraries like SQLDelight or Room (which now supports KMP).

You define your database schema in one place. You write your SQL queries in one place.

The generated code handles the platform-specific drivers.

Your Android app uses the SQLite driver. Your iOS app uses the Native driver.

The logic governing how you save, retrieve, and delete user data remains identical across both platforms.

3. The "Brains" (ViewModels)

This is where things get really exciting.

You can actually share your ViewModels.

The ViewModel is the component that holds the state of your screen. It decides what happens when a user clicks a button. It decides what to show when the network fails.

This is pure logic. It has nothing to do with pixels.

By sharing the ViewModel, your UI becomes incredibly "dumb"โ€”which is a good thing.

Your SwiftUI view just observes a state object from the shared Kotlin code.

If the state says isLoading = true, the UI shows a spinner.

The UI doesn't need to know why it's loading. It just follows orders.

How It Works: A Technical Peek

I know what you are thinking.

"This sounds great, but is the setup a nightmare?"

It used to be. But the ecosystem has matured massively in the last year.

Letโ€™s look at the project structure.

The Source Sets

A KMP project is divided into "Source Sets."

First, you have commonMain.

This is where 90% of your code lives. This is pure Kotlin. It contains your models, repositories, and logic.

Then, you have androidMain and iosMain.

These folders are for platform-specific code.

If you are writing a pure algorithm, it goes in commonMain.

But sometimes, you need to access a specific device feature, like the Camera or Bluetooth.

Kotlin doesn't know how to access the iOS camera by default.

The Expect/Actual Mechanism

This is the bridge between the shared world and the native world.

It acts like an Interface, but at a language level.

In your commonMain folder, you might write:

expect fun getPlatformName(): String

The compiler will now complain. It will tell you that you promised a function, but haven't provided the implementation.

So, in androidMain, you write:

actual fun getPlatformName(): String = "Android"

And in iosMain, you write:

actual fun getPlatformName(): String = UIDevice.currentDevice.systemName()

Notice that in iosMain, I can access UIDevice. That is an Apple API.

I can access it directly inside Kotlin because KMP has access to the iOS SDKs.

This mechanism allows you to share high-level logic while still dipping into native capabilities whenever you need to.

The Real-World Benefits

We implemented KMP on a recent project at My Core Pick.

The results changed how I view mobile development.

Consistency is King

The biggest benefit wasn't speed. It was consistency.

We had a complex calculation for a "Health Score" in the app.

In the past, the iOS dev would interpret the requirements one way, and the Android dev another way. We would end up with slightly different scores for the same data.

With KMP, we wrote the algorithm once.

We unit tested it heavily in Kotlin.

We deployed it.

We knew for a fact that if a user switched devices, their score would be exactly the same.

Faster Feature Iteration

Once the architecture was set up, adding new features became significantly faster.

When we needed to add a new API endpoint, we added it in the shared module.

Suddenly, both the iOS and Android developers had access to it instantly.

We didn't have to wait for the iOS developer to catch up on the networking layer.

It creates a "relay race" dynamic. The core logic developer clears the path, and the UI developers sprint to the finish line.

Supercharged Testing

Testing UI is hard. Testing business logic is (relatively) easy.

Because our logic is separated from the OS, we can run our tests on the JVM.

This is blazing fast. We don't need to launch an Android Emulator or an iOS Simulator to test our ViewModels.

We write standard JUnit tests. They run in milliseconds.

This encourages us to write more tests, which leads to a more stable product.

Is It Ready for Primetime?

You might be hesitant to adopt a new technology.

That is a healthy skepticism.

However, KMP is used by giants.

Netflix uses it. VMWare uses it. McDonald's uses it.

Google officially supports it.

The ecosystem of libraries is thriving.

For Dependency Injection, we have Koin.

For Networking, we have Ktor.

For Logging, we have Napier.

The tools are there. The support is there.

Conclusion

We are in a new era of mobile development.

The days of strictly siloing iOS and Android logic are ending. It simply costs too much money and time.

But we also aren't willing to sacrifice the quality of native UIs.

Kotlin Multiplatform hits the sweet spot.

It respects the platform differences where it matters (the UI) and unifies the platform similarities where it counts (the logic).

Stop writing the same code twice.

Stop fixing the same bug twice.

Start sharing your business logic. Your codebase (and your sanity) will thank you.


Enjoyed this deep dive? Check out more technical insights right here on My Core Pick.

๐Ÿ”ฅ Share this Insight

๐• Post
Sharing business logic between Android and iOS applications using Kotlin Multiplatform (KMP).

Stop Writing the Same Code Twice: Sharing Business Logic with Kotlin Multiplatform

Here is a blog post written specifically for **My Core Pick**. *** # Stop Writing the Same Code Tw...

My Core Pick.
mycorepick.com

Advertisement

Back to Posts