· 7 min read Posted by Kevin Galligan

Basic Concepts

KMP For Native Mobile Teams

To prepare for the discussion of KMP approaches, we need to clearly define some terms and concepts.

This is a post series with several sections. If you landed here first, make sure to go back to the Intro to get the full story.

Overview

There are two basic concepts which will be critical to understand while reading through this post series and planning to adopt KMP: Development Modes and Code-sharing “Flow”.

Development Modes

In the context of KMP and native mobile teams, there are two basic “modes” of development: Library Dev and Feature Dev. The distinction between the two is intuitive to any experienced developer, but requires clear definitional boundaries to facilitate discussion.

In summary:

  • Library Dev is how we build “libraries”. Self-contained, self-defined, separately-developed modules. Generally published linearly (2.5.4, 2.5.5, etc.).
  • Feature Dev is the day-to-day development in any project. This code implements a “feature” of the project. For native mobile, this is the UI and architectural underpinning code that implements that “feature”.

Code “Flow”

The code “flow” is also a simple concept, but less obvious as it’s rarely framed in a way similar to how we’ll be framing it. Code “flow” is how code/logic moves between modules. In the simple case, if you publish a library, that library dependency is pulled into another project. It “flowed” from the library repo/CI to another project.

In the context of KMP, teams generally either publish libraries from a KMP repo, or co-locate the KMP code with the native app code, in the same repo. The “flow” for those two options would be unidirectional and non-directional, respectfully.

We are defining this concept in the abstract. First, to differentiate the specific “how” from the outcome. Second, because we’re defining a relatively new model.

Exclusive Section

Producing content, especially content that isn’t strictly “technical”, is difficult in a vacuum. To browse the remainder of this series, please fill out this short survey. Understanding who is interested helps us produce better content going forward.

Javascript disabled?
Our site requires Javascript for some sections. Please check that Javascript is enabled.

In Detail

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

For these kinds of teams, the approach to piloting KMP is almost universally adding a 3rd repo with the shared 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.

From a conceptual standpoint, this approach involves a “Library Dev” model.

Library Dev

This approach is called “library dev” because it models how any shared library is built. Not KMP specifically. Any library. The code is developed separately, and included as dependencies into other projects.

Library dev is used for discrete, external modules, whose definition and lifecycle is not bound by the day-to-day concerns of direct feature development. This code generally does not change much, is tied to external constraints and/or timelines, and is often edited by a smaller group of devs from the app team, or a different team altogether.

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 app features, but changes are infrequent (migrations), and are incrementally versioned
  • Tax calculation. Complex and critical code. Best written once.

Diagram of an external library repo

Code in an external library repo tends to have fewer changes, but more importantly, fewer conflicting changes. Even in a situation where the library code may have many developers and internally conflicting changes, the output is explicitly linear, and published much less frequently than the actively developed code in your main project.

With KMP

In the context of KMP, most teams go through a “piloting” phase. This phase usually involves a library dev model. Publishing a KMP library is relatively easy to set up and introduce, because it does not significantly disrupt existing development workflows. However, it does not scale.

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 use 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 developer. Feature dev changes are frequent. The code itself often has merge conflicts that must be resolved. Git provides complex operations that are critical for building complex projects.

With KMP

When thinking through your KMP adoption plans, it’s important to internalize the difference between library dev and feature dev. We’ll discuss in detail later why teams struggle in the “scaling” phase, but its worth mentioning now.

Scaling KMP means feature dev. The bulk of the code in most apps lives with the features. To realize the potential efficiency of KMP, your team needs to be doing KMP feature dev.

Put more generally, the bulk of the code in any project with multiple engineers will, for obvious reasons, be getting lots of changes. Forcing those changes through the library dev bottleneck will seriously impact efficiency.

In most projects, there’s only so much code that falls into the “Library Dev” category, which limits how much code you can share, which ultimately limits KMP’s efficiency gains.

More generally, if your workflow model is not designed to handle a lot of code change, it won’t represent the bulk of your code. It simply can’t.

Slide of a see saw with relative native and KMP code

Library dev and feature dev are a more explicit refinement of the 4 “modes” I discussed in last year’s KotlinConf talk on KMP and teams. Mode 3 involves building some portions of the app with shared UI. Touchlab is very excited about this possibility, but it is a different topic with different considerations. Mode 4 is fully shared UI. Best-practice for mode 3, and certainly 4, would be very different than that for feature dev and native UIs.

Code Flow Directionality

Code flow directionality is a conceptual way of looking at how code is shared. Structurally speaking. To avoid discussing specific, mechanical methods of sharing code, the “directionality” model focuses on the “what” vs the “how”.

Unidirectional

The KMP code is in one repo, the apps in their own repos. Code changes flow in one direction.

When we’re talking about “library dev”, with versioned, published builds, that’s unidirectional.

For KMP, this generally means “publishing binary dependencies”, but it doesn’t need to.

Our current recommendation for teams piloting KMP is to share code rather than binaries. If the goal is to increase team adoption and expose the iOS developers to Kotlin, sharing binaries is a waste of time.

We will be discussing unidirectional models with source code in later sections. Rather than focusing on the exact “how”, “unidirectional” is agnostic to the specific mechanism, but all unidirectional implementations share similar implications and outcomes.

This is, of course, not specific to KMP. Any library you use has essentially a unidirectional code flow model.

Specifically: KMP —> App. Generically: SDK —> Consumer.

Diagram of a KMP repo with arrows to app repos

Non-directional

Code doesn’t “flow” anywhere. It’s a “monorepo”. It’s an odd concept to define outside of this context, and we’ll mostly say “monorepo” rather than “non-directional”, but they’re effectively the same thing.

Non-directional basically means that all code is changed as a unit.

Diagram of a monorepo with KMP and app modules

We’ll generally say “monorepo” rather than “non-directional”, as it’s more familiar to readers. Some people object to using the term “monorepo” if the repo doesn’t include everything (back end, etc). For our discussion, the term “monorepo” is only referring to the mobile code.

Bidirectional

KMP code flows in both directions. From app repo to KMP, from KMP to app. We’ll give a much longer description later, when we get to “scaling”. For now, just know that this is also one of our formal directional models.

Diagram of a KMP repo with arrows to and from app repos

It’s a fairly unique concept, but it does help solve some of the issues created by doing feature dev in a monorepo.

Next Section : Getting Started

Time to dive in. The next section will be an overview of the phases and some ideas to consider when thinking through KMP adoption plans.