Dividing Kotlin Multiplatform work in teams
Tags: kotlin, kotlinmultiplatform, productivity, mobile
Published: 2022-02-28 19:02:28

Kotlin Multiplatform is a great way to share code between multiple platforms, but this new approach can be confusing to  navigate. There's a variety of sourceSets for platform specific code, plus intermediate sourceSets(such as `mobileMain`) that cover multiple platforms at once. One of the difficulties that can arise is how to divide work among your team.

This gets more difficult the larger your team is and the more platforms you're developing for. It sounds straightforward at first: the iOS developer works on the iOS code, the javascript works on the JS code, and so on. In practice however, you may run into unforeseen challenges. 

## Challenges

 * __Languages__: KMP is of course written in Kotlin, but if you have iOS developers or Javascript developers that only know Swift or JS, then there's going to be a learning curve. 
 * __Android Bias__: You may think if you're writing Kotlin code then get the Android developer to do it. Not only are you pushing all the work on your Android devs, but there's chances for Android biases in their code.
 * __Conflicts__: If you have all devs working on their own platforms at the same time, that can lead to conflicts when merging PRs and arguments about the best approach.
 * __Assigning Tasks__: Beyond writing code there is an issue of issue tracking. When assigning work how do you know who's working on what layers? An Android task could include shared code. 

So how do you assign work to multiple developers effectively, without causing the team to step on each others toes?

## Our Approach

The best approach we've found is to split up the work into two camps: 

`PlatformSpecificUI` and `KMP`

For example, if our project is written for Android, iOS and JS we'll have four groups:

`androidUI`, `iosUI`, `jsUI` and `KMP`

This again may sound straightforward, but there are some things worth mentioning. First let's visualize the layers.

![KMP Layers](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/oit0vnm248d8bjgtwzge.png)

Here we can see the different layers in our example. We have:
`androidMain, iOSMain, jsMain, mobileMain and commonMain`

So in our example we have the four groups and their work:
 * __androidUI__ works in `androidMain` and the Android layer
 * __iOSUI__ works in `iosMain` and the iOS layer
 * __jsUI__ works in the js layer
 * __KMP__ works in `commonMain, mobileMain, and jsMain`

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/sggerzv3gf59bdw4hx79.png)

With this approach all the platforms are dependent on the __KMP__ groups work(The common layer).

## An Example

So as an example, we want to add a new feature: 

> A new screen that fetches an image from an api and displays it when a button is pressed. This feature will be on every platform, and it's going to be tracked via an issue tracker.

![Division of Work](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/bwk943d662p8ikaezmqd.png)

Above we have an example of what your architecture might look like a lot at first, but let's go over it.

In Android, we have:
`Fragment -> ViewModel -> Coordinator -> Repo -> network api`

> A button is pressed in the Fragment, an action is sent to the ViewModel which using a coroutine calls the coordinator. The coordinator then gets the image from the repository and processes it to bring back to the ui. 

A similar flow can be seen for iOS and Javascript, but with their own implementations. In this example we have the interfaces `RepositoryCommon` and `Api`, which are then implemented platform specific.


#### Splitting the work

You may be asking why the `jsUI` doesn't work in `jsMain`, while the other two groups work in their respective sourceSets?

It's better to think of it in this way:
> The KMP group is working on the common code and its implementations

In the example above the KMP group is working on the CommonRepository, as well as the implementations. They even work on the next level up(The Coordinator and js Service). The Coordinator and service are still in business logic, and despite having their own platforms they are still using shared libraries.

## Why this approach

This approach prevents some of the issues mentioned prior:

 * __No platform delays__: Since all the platform specific work relies on the __KMP__ groups work, there is no one platform that has an extra workload and all platforms start at the same starting line.
 * __Increasing Platform Knowledge__: The __KMP__ group creating the groundwork for all the different platforms means that they can grow their knowledge of all the platforms in development.
 * __No conflicts__: All the platforms relying on the common layer ensures that all the platforms are in agreement with the business logic before working on the platform-specific code. 

__Note__:With this method all platform developers would review and approve this foundational code, to make sure it fits all their requirements. This also helps maintain feature parity across platforms, and avoid platform biases.


#### Platform Equality

One key issue that I think a lot of KMP developers struggle with is platform equality. It's easy to start with the Android implementation since it's in Kotlin and the KMP library is easily debuggable. This approach puts a focus on Android, and other platforms can lose out because of it. They're seen as afterthoughts and don't get as much focus as Android.

A small example is that lists are not supported in KotlinJS, so if the developer starts using lists in the android implementation they may not notice until the JS project is built.

One of the advantages to having one group work in KMP is that it gives even attention to every platform, as the KMP developer has to write code with all the platforms in mind.

## Layer Intermingling

There are some issues that may come up, especially when working between business and UI logic. Developers have different levels of experience in languages and Platforms, so crossing the bridge between logic layers can be tricky. 

Examples of these issues are:
 * __Platform specifics__: shared code can still call platform libraries, such as `iosMain` calling `Foundation`, so Kotlin developers may not know these libraries.
 * __Different Languages__: In our approach platform developers are working in Kotlin sourceSets(i.e. an iOS developer has to work in iOSMain). An iOS dev may be familiar with `UIKit` and Swift, but is unsure how to write the code in Kotlin.

In cases like this where a there is an intersection between shared code and platform specific code, pair programming is a great option. Not only does it ensure that the code meets both sides' requirements, but it encourages knowledge sharing.

The __KMP__ developer working on the shared code can create a base implementation, then work alongside the platform-specific developer to find the best approach to the issue. All the while both developers are sharing their knowledge of Kotlin and platform-specific code. 

## Downsides

The main downside to this approach, is that the KMP dev cannot easily test their implementation. For example if they are writing a network call and tries to serialize it into what they think the format is, it's only until one of the platform developers implements the call that they will realize it's incorrect. 

One way to get ahead of this issue is to create tests whenever possible. Testing network layers can be tricky, but writing some form of test to make sure your code works for the platforms will help nip these issues in the bud.

If there is an issue like this, then it should be communicated with the team so that the other platform developers know that there is an issue, and the team can work to resolve the bug.

## Conclusion

Every team is different, and every project is different. While this approach may not suit everyone, at Touchlab we have found that it can help organize work and increase knowledge sharing. 


Thanks for reading! Let me know in the comments if you have questions. Also, you can reach out to me at @kevinschildhorn on [Twitter](https://twitter.com/KevinSchildhorn), or on the Kotlin Slack. And if you find all this interesting, maybe you'd like to [work with](https://touchlab.co/contact-us/) or [work at](https://touchlab.co/careers-3/) Touchlab.