KMP For Teams

(Draft) KMP Team Adoption Patterns

· 7 min read

Author: Kevin Galligan
Teams tend to adopt KMP using existing development patterns. We'll briefly discuss them, and why those patterns create issues

Draft Document

This doc is a work in progress.

As mentioned in the intro, we are focusing here on native mobile teams, comprised of platform “specialists”. While these team may collaborate to a greater or lesser degree, they’re generally separate. The app code is often in separate repos, and the teams often have their own workflows and conventions.

For these kinds of teams, the approach is almost universally adding a 3rd repo with KMP code. This code is developed on its own, and dependencies are published and consumed by the native apps.

This is so common, Touchlab created KMMBridge to make this process easy to set up.

This approach definitely “works”, but it is limiting. You cannot really share a lot of code. To help explain many concepts presented in this guide, we’ll start defining some formal terms.

KMP Development Mode 1: Library Dev

This approach is call “library dev” because it is how you would approach any shared library. The code is developed separately, and included as dependencies into other projects.

It also aligns well with the “piloting” phase of KMP adoption. When the team is “trying it out”. You don’t need to disrupt their regular development work.

The code at this stage generally implements smaller, discrete “modules” for the apps. Code that is not directly impacted by day-to-day feature development. This code also generally does not change much, and is often edited by a smaller group of devs.

Examples:

  • Server calls. Server APIs are defined by the server developers, and change on their own schedule
  • Local DB storage. This code is often more directly tied to feature dev, but changes are infrequent (migrations), and are incrementally versioned (like the library itself)
  • Tax calculation. Complex and critical code. Best written once.

Diagram of a monorepo with KMP and app modules

Code in an external library repo tends to have far fewer changes, and more importantly, fewer conflicting changes. Releases are published with linear versions.

With KMP

This is easy to set up, and most teams committed to trying KMP can usually implement this model successfully. However, it is limiting. For most projects, there’s only “so much” code that will fit well into this category.

KMP Development Mode 2: Feature Dev

Feature dev is the day-to-day coding work of app teams. It’s called “feature dev” because you’re generally implementing an app “feature”.

In simple terms, this is the app’s screens, logic, and “architecture”. A team with multiple devs, or even a single dev working on multiple branches, will often have conflicting changes. This is essentially why we have source control. Feature dev would be chaos without it.

Diagram of a monorepo with KMP and app modules

The code in a “feature” is edited as a unit. The UI, and the architecture that supports them, are usually edited together, by the same dev. Feature dev changes are (hopefully) frequent. The code itself often has merge conflicts that must be resolved. Git provides complex procedures that are critical for building complex projects.

Why teams struggle scaling KMP

When thinking through your KMP adoption plans, it’s important to internalize the difference between library dev and feature dev. These different models are at the core of what’s difficult about adopting KMP (besides the other things that can make it difficult, but stay with me).

KMP is unique

KMP falls into the “shared code” category if “cross platform” technology, but it has attributes which are rather different than other shared-code options.

Most shared-code is written in a different language, often by different developers. The interop is generally poor. The library ecosystem specific to native mobile is usually limited or non-existent, depending on the particular technology.

All of that creates “distance”. The shared code is usually difficult to call and deal with, not to mention update and maintain. It rarely changes, and is generally doing something really valuable. It needs to be, because the “cost” of having it is high.

External, published libraries make perfect sense when there’s a lot of “distance”. KMP, however, closes that “distance” considerably. To the point where feature dev, virtually unthinkable with other shared-code options, is not only possible. It is, for many, the goal, and where the bulk of KMP’s potential lives.

It is KMP’s unique place in the “shared code” ecosystem that should be understood. Most “shared code” is developed in a library dev model, and the slow pace of change isn’t a problem. Naturally, many teams try the same model with KMP, because KMP is “shared code”. But it is shared code with much less “distance”, that should be directly involved in feature dev.

KMP needs new models.

Scaling Means Feature Dev

In theory, KMP can provide all of the app’s “logic”. The data, functionality, architecture, etc. In simple terms, “everything up to the screen”. That’s the potential.

As stated, most teams start with an external repo, doing “library dev”. That’s fine. Where that hits a wall is when teams decide to start doing feature dev with that same repo structure.

Diagram of a monorepo with KMP and app modules

The architecture code involved in feature dev now lives in the KMP repo. It has its own lifecycle and is published with linear versions.

However, feature dev is characterized with frequent, conflicting changes. That’s one problem. Also, the UI and architecture code are no longer being developed as a “unit”. That is painful and inefficient.

The KMP repo has its own PR and approval process. This will add significant process overhead. Worse, changes to KMP impact both platforms. A feature added to the external repo would also generally need to be implemented for Android and iOS at the same time.

That means:

  • KMP changes, review, merge, release
  • Pull those changes into both Android, then iOS, implement screens. Then those changes go through the app-specific review and merge process

Multiple devs will be making concurrent changes to KMP and the apps. Pulling in versioned KMP libraries for the “logic”, then using them in “fully concurrent” code under source control, is very difficult to do with any reasonable velocity.

In short, it simply doesn’t work.

Moving to a monorepo

To support feature dev, most teams move to a “monorepo”. In this context, I mean they pull the Android, iOS, and KMP code into a single repo.

There’s a bit of a disagreement on the term “monorepo”, as its generally used to mean all of the product code. Back end, web, mobile, etc. In this context, we mean just the native apps, although you could actually have everything in a monorepo, and it would be the same result.

A monorepo solves several of the problems involved with feature dev using a library model.

  • Supports frequent, conflicting changes
  • Feature code is edited as a unit
  • Less “paperwork”. Fewer reviews, less waiting on releases, etc

While that is certainly better than published libraries, monorepos introduce their own issues. Again, details in a later post, but some quick observations.

KMP changes immediately impact both platforms

If you’re making a change to the Android app that involves KMP changes, “something” needs to happen with the iOS side. You can’t (safely) just commit that code. Approaches vary to this problem, but none are ideal.

I gave a talk on teams and KMP at KotlinConf 2023. This issue in particular was an open question I left off with. After talking to several engineering managers, nobody really had great approaches. We have some new ideas now, though.

Teams and apps are coupled

Because the KMP code changes at the same time, app dev has to happen at the “same time”. This isn’t always a huge issue, but it’s not ideal for a number of reasons.

Among the issues is one that should get some more consideration. Native app development efficiency. One of the “deep dive” sections goes into this, although I think it’s a topic that should get more consideration and research in the KMP team context.

Merging teams is risky

For some teams, merging the repos is part of the goal of “merging teams”. Instead of mobile platform “specialists”, all of the devs should learn KMP and be able to edit code for both platforms. Turning “Android devs” and “iOS devs” into “Mobile devs”.

We’ll certainly have more to say about this later, but its a risky plan and even when things go reasonably well, it won’t be smooth.

Not that you can’t do it, but you should be aware of, and attempt to minimize, the risks.