Hello How are you guys organizing your KMP project...
# multiplatform
g
Hello How are you guys organizing your KMP project as far as git repositories go? In my project we started by using git submodules for the shared module and the iosApp but that makes CI/CD pipelines difficult to manage; for example it is hard to have a pipeline that runs UTs for the shared module when an MR on the project is opened. I am now considering switching to a mono repo for everything: android, shared and iOS but I would like to gather some feedback on the matter.
r
(Independent of KMP, I've always found git submodules to be hard to use) I think one repo is definitely the way to go for a single application, even if it's built for multiple platforms. I think it really comes down to how different artifacts' versions should be coordinated: together or separately. If you have one repo for e.g. shared lib + iOS + Android, • an update to the shared lib should also come with an update to both iOS and Android • an update to just iOS or just Android without anything else can be just that If you really wanted your shared lib to version independently, then I'd put it in its own repo and just publish its artifacts to a place the other repo(s) can grab the exact version needed. That shouldn't be necessary just for the core logic of a single app, though.
(Though I'll also point out that you shouldn't need to re-run unit tests for the shared lib when you're making a change to the iOS or Android app. I'd say you only need to run tests on the shared lib when the shared lib changes)
a
Touchlabs have provided very useful guidance on what might work best and where for who: https://touchlab.co/kmp-teams-use-source And higher level https://kotlinlang.org/docs/multiplatform-advanced-project-structure.html#compilations We use a mono-repo for the source of 7 published libraries with 15 variations of front-end apps ~ 80k lines of both kotlin and swift code. It allows us to share gradle convention plugins, and keep versioning, dokka samples etc all sync'ed along with any refactoring. We use fastlane to manage the different build tasks, tests, versioning, dokka, publishing and deployment. so the dev can match the same lanes and build variants as the CI. I don't experience any issues with compile times for debugging, and we use the CI to store and fetch release artifacts.
m
I've been through various iterations of experimenting with different ways of sharing KMP modules and it ultimately boils down to what the team is most comfortable with and what they're also comfortable explaining to new joiners. I find that good documentation is necessary regardless of whatever approach is taken. A single (monorepo) is good but probably not always ideal, especially with larger teams with already existing workflows and setups. Sometimes, teams built like this prefer to leave their codebase separate and rely on a third shared module for KMP. In my previous workplace, they started with copy-pasting the shared KMP code since the Android and iOS codebases were completely separate. The first initiative I implemented was to use git submodules for the shared module. It was painful integrating this with Github actions and Bitrise, but eventually worked out. The unit tests were written in the shared module and I don't recall us ever having a scenario where we needed to run unit tests again after making a change to the Android or iOS code. Tests that were platform-specific were run on their respective platform modules. Managing the versions became hell though, especially for our git flow - we had to seek out certain commit hashes to push hotfixes and their respective commits which Android and iOS pointed to in the shared module were almost never in sync. Then to top it all up, there's the fact that not everyone is familiar with git submodules and that always led to inconsistencies and confusion. The most promising outcome involved using Touchlab's KmmBridge to publish Xcframework binaries to SPM while using maven to publish for Android. With some CI/CD manipulation, backed by extensive documentation on what we should do in certain scenarios, this enabled us achieve a consistent way of pushing out new code. It's a bit ironic that Touchlab did a 180° and recommended the opposite in their https://touchlab.co/kmp-teams-use-source article. It felt like a breath of fresh air, particularly for the iOS developers when they just had to use SPM for the latest KMP code changes. I hooked it up via Github actions to be created on PR events, so creating a PR on the shared KMP codebase created a new SPM build which was uniquely identified by the library version + the unique incremental PR number. Surprisingly, this ended up making the iOS developers even more eager to write KMP code since they could easily experiment and test with SPM. And just like with git submodules, the unit tests on the shared module weren't affected by changes to the platform modules.
🙌 1
a
Git submodules is the most cumbersome imho
If you can monorepo then do it
As always it depends on your circumstances
k
Has anyone tried git subrepo? It seems to solve many of the problems with git submodule https://github.com/ingydotnet/git-subrepo
g
thanks all for the replies I agree that submodules are cumbersome, but we have been working with a setup using submodules for about 1 year, so the team is comfortable with the workflow using this setup. right now the only downside seems to be a more complicated ci/cd setup. How do you guys work as far as branching strategy goes? I assume with a mono repo a gitflow strategy would work ok, but that means that a feature branch would contain changes for all 3 modules: android, ios and shared and that would mean 3 reason for that branch to change. Also, 2 people would work on it: one Android, one iOS and one of them working on the shared module too. That requires some good communication and sync between the 2 devs.
a
So with git modules the devs don't need to communicate? KMP already implies more communication/coordination between devs since the thing is shared. All changes in shared code should be approved by the parties consuming it.
I imagine in submodule setup a dev does some changes in the shared module and then is ignorant of what the consumers are doing, or what happens on the consumer side. In a monorepo you would see what went wrong by the compiler first, then by the ci test if there are any.