Hey everyone, question about project structure for...
# ktor
s
Hey everyone, question about project structure for a project which should hold both a
Ktor
service and a Kotlin multiplatform setup with a JVM (Compose Desktop) client target. Considering Kotlin Multiplatform currently doesn’t support having multiple JVM targets, I’ve set up my project modules as such:
Copy code
- :common -- Holds all common code (business logic / models) shared between Ktor & the desktop target
- :backend -- Holds the Ktor service
- src/commonMain -- Main project module, holds the common code for clients
  src/desktopMain -- Main project module, holds the desktop-specific code
Whilst this setup seems quite basic and straightforward, it seems to bring a few unexpected drawbacks which I’m trying to fix: • The Ktor service has its own dedicated Gradle ‘run’ task triggered by
backendRun
, but the desktop target does not (there is no
desktop:run
task). To start the desktop app, I need to trigger the general Gradle
run
task, and this one will always first start another
backend:run
task first, and after killing it and running it again, it will start the desktop app
◦ Resolved • Once I trigger a task to run using the dedicated “Run” button in the Intellij IDE (or just press
CMD/CTRL + R
), I’m unable to restart the task by pressing the button again before I manually terminate the process. I really have to go into the “Run” section (
CMD + 4
) and close the tab before Intellij allows the task to be restarted. • I am unable to restart the Ktor service with an identical port number, as it will always complain about the port already being taken. So I had to resort to opening a new
ServerSocket
at the start of the Ktor process and dynamically acquiring a free port. The downside to this is that whenever I restart the backend task, I need to copy the port number and paste it into the client code (and restart the client) to make sure that my desktop app is able to address the REST API on the right port number. Is there a way to make this more straightforward as well? Sorry for the big post, and thanks for all help & suggestions!
c
Your problem is that Gradle inherits tasks from parent projects to children projects (e.g.
a:run
implies
a:b:run
), which is not what you want in this case (but in the general case, it's convenient, because it makes
:test
run the tests of all projects). I don't know if this can be configured, but I usually don't put code in the root module. What I usually do:
Copy code
project root/
  common/
  backend/
  app/
This way,
backend:run
is unambiguously starting the backend, and
app:run
is unambiguously starting the app.
You can see this pattern in action in this project: https://gitlab.com/opensavvy/clovis (backend, Android, Desktop and Web) Don't look at the code too much, it's just a prototype that does nothing at the moment, but the Gradle setup is in place
s
I assumed the top-level definition for the clients could’ve been the issue, but I wasn’t sure whether the multiplatform setup would still work in a submodule. So thanks a lot for your project reference, it will definitely help a lot in resolving this!