Do people in general create smaller modules? Even ...
# getting-started
l
Do people in general create smaller modules? Even after years of using Kotlin, I still am not sure about how I feel about modules. I have a main module where the core of the application goes, but inside it, there is of course a more granular layout in various packages etc. However, since there is no package protected visibility, everything is visible to everything else. It seems as though Kotlin was designed with the idea that you'd have lots and lots of small modules, many of them being just a single file. Is this what people do?
This is the code for the main module by the way, in case anyone is interested. https://codeberg.org/loke/array/src/branch/master/array/src/commonMain/kotlin/com/dhsdevelopments/kap
k
In my experience, most Kotlin projects I've worked on have at most 5 or 6 modules, each of which contain many dozens of files. Why would you have a module with a single file? You could just make everything in it private.
y
I personally find some friction when wanting to introduce a new module. Having to set up the gradle config for it is just too much of a headache, so I end up skipping it.
f
maybe the usage of explicitApi should help you to organize your code
j
its not really about how big it is, its about how you need to cut and slice those things, usually into deployments. it is hard to create sub-units of a module by package (i've done it in java, but really its too hard for normal use!), so modules give you boundaries that are easier to enforce. but you can use ArchUnit if you are worried, maybe? - although tbh never tried with kotlin.
j
In the Amper project, we tend to use many modules to separate logical units more precisely. I prefer to limit the visibilities of declarations as much as possible, and internal visibility is great for this. With Gradle projects it's a bit less convenient but in Amper it's easier
l
In my case, I have quite strict logical separation between sub-components. However, I believe it would be difficult for other people to contribute, because this separation is not enforced. There are certain public functions that really should never be called outside certain contexts, but they still need to be called from other files (so
private
is not sufficient)
y
I feel like IntelliJ could help a lot here. I'd be much more inclined to use multiple modules if I could just choose a bunch of files, and magically create a new module out of them (with it figuring out dependences, compiler arguments, etc). What'd be even nicer is if IntelliJ could auto-detect (using some graph theory magic) strongly-connected declarations, and suggest to move them into their own module, making most of them internal, while keeping the necessary functions public.
πŸ‘€ 2
j
Have you considered maybe other ways to achieve what you want? Like extensions, or having different interfaces for different purposes... Intellij cant rename or move a kotlin method reliably right now! 🀣
l
@James Richardson don't get me started...
Anyway, I do what I can to make it clean, but like @Youssef Shoaib [MOD] said, it would be nice if there was less friction in creating modules. But this will easily lead me into a rant about gradle.
a
My main project currently consists of ~10 modules. I've, at this point, developed a habit to lay out the project in modules first, code later, so that I don't have to do the separation once I want to compile e.g. a worker binary in addition to a web API. The most horrid part of it all is managing Gradle. I really cannot wait for Amper to stabilize soon enough.
Included/composite builds do make it slightly easier to manage smaller modules, but setting that up in itself has demotivated me for a very long time
r
We have a codebase that aggressively uses gradle subprojects to enforce architectural rules and speed up the build by not having to repeat large amounts of the work. At time of writing here are the stats:
Copy code
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”                                                                                                                                                                                                                                                                                                                                                                                             
  β”‚        Metric         β”‚ Count  β”‚                                                                                                                                                                                                                                                                                                                                                                                             
  β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€                                                                                                                                                                                                                                                                                                                                                                                             
  β”‚ Production code files β”‚ 257    β”‚                                                                                                                                                                                                                                                                                                                                                                                             
  β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€                                                                                                                                                                                                                                                                                                                                                                                             
  β”‚ Production code lines β”‚ 22,707 β”‚                                                                                                                                                                                                                                                                                                                                                                                             
  β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€                                                                                                                                                                                                                                                                                                                                                                                             
  β”‚ Test code files       β”‚ 146    β”‚
  β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€
  β”‚ Test code lines       β”‚ 54,048 β”‚
  β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€                                                                                                                                                                                                                                                                                                                                                                                             
  β”‚ Gradle modules        β”‚ 58     β”‚
  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”˜
So averaging 4.5 production files and 2.5 test files per module. The major negative is the ridiculous nesting gradle conventions have -
src/main/kotlin
over and over again. In the past I've overruled the convention in favour of separate
src
,
resources
,
tests
and
test-resources
directories in each project's root... Dropping a build.gradle.kts in each project's root is OK, they nearly all are just this:
Copy code
plugins {
  id("buildlogic.kotlin-library-conventions")
}

dependencies {
  ...
}
I'd love something a bit lighter - JVM only it'd be great to use JPMS in the way described here: https://gradle-community.slack.com/archives/CAHSN3LDN/p1740405046542339?thread_ts=1740392114.765959&cid=CAHSN3LDN
k

https://www.youtube.com/watch?v=ayJ_WJ-8zHoβ–Ύ

l
@Rob Elliot that's a lot. My project is about 110k lines over 625 files (about 1500 non-synthetic classes). There are 34 modules, but about a half to 2/3'rds of the code is in a single module.