I’m evaluating Couchbase Lite for a project I’m building with Kotlin Multiplatform. The idea is to have most of the code in a pure Kotlin module and then build as little platform-specific code as possible to glue everything.
My target platforms are the JVM and Android, so I have an artifact for each: com.couchbase.lite:couchbase-lite-java and com.couchbase.lite:couchbase-lite-android-ktx. So far, so good.
The problem is that there is no common artifact both of them include, so even if 99% of my repository classes are the same in Android and in desktop (only the way to create a Database instance changes a bit, by needing the Android context and there are tiny changes in some factories), I’m forced, unless I’m overlooking something, to duplicate all my methods in both modules. It works, but it feels dirty.
If I only had an artifact with interfaces for Database, MutableDocument, etc. that both the Android and the JVM library included transitively, I could include that one in my common module, implement there all the functionality and just leave the constructors themselves for the specific platforms.
Is there any other way you can think of achieving this code reuse? Is this something in the dev team backlog?
Couchbase Lite does not, at the moment, support Kotlin on the JVM. The Kotlin extension package, couchbase-lite-android-ktx is Android only.
In addition, you are quite correct that the Android platform is substantially different than the JVM platform. Our internal source structure is almost identical to yours: we have a big bunch of common code with thin adaptation layers for each of the 6 specific platform that the “Java” group supports: JVM, Android and Android Kotlin extensions, for each of the two variants, Community and Enterprise.
Here is my suggestion: We try very hard to make sure that the JVM and Android APIs are identical. I would think that you could write all of your code, pretty much agnostic to which of the two libraries it will use, at runtime. The android version of your product would be based (like ours!) on a large base of common code, a top end shim for for the target platform, and the appropriate back-end CBL library, for that platform. The JVM version would be a different shim and a different library.
If our code is any guide, that should work for you and be relatively easy to set up, with gradle.
Thanks, Blake, that’s exactly my idea. Nevertheless, for the common code I would need something that doesn’t depend on either Android or the Java standard library. Pure Kotlin would be fab, but something like just Java interfaces for Database, MutableDocument, etc. would also work. Platform libraries should include them transitively and implement them with their own tweaks. But I need some Couchbase types to use in my common module.
Just to ensure I’m not misunderstanding you, this is an excerpt of my Gradle build:
sourceSets {
val commonMain by getting {
dependencies {
// What artifact could I put here?
// I need common superclasses or interfaces of both the Android and the JVM types
// to write common code, as queries, converting from domain objects to documents, etc.
}
}
val androidMain by getting {
dependencies {
implementation("com.couchbase.lite:couchbase-lite-android-ktx:$couchbaseVersion")
}
}
val jvmMain by getting {
dependencies {
implementation("com.couchbase.lite:couchbase-lite-java:$couchbaseVersion")
}
}
}
Is there something I’m overlooking? I appreciate your help.
By the way, I copied parts of the ktx library to my JVM target (like QueryToFlow) and everything worked without a hitch. I suspect that most of the extensions could be migrated to JVM without having to write any additional code. As a fan of Kotlin for backend and desktop, I really encourage the team to do so, officially, before I publish that to my Github.