Why maintaining an open source app is hard…

Maintaining open source projects is not for the faint of heart. Beyond technical competence it requires commitment and dedication, being able to organize and plan time carefully not only to deal with actual implementations but also for triaging user requests/reports, managing public relationships, reviewing external contributions, organizing internal workforce, etc.

It can be daunting, especially for projects maintained by few people (or just one person) in their spare time, considering we all have our regular jobs, families, hobbies, etc. Working on an application other people use in their day by day can be a great responsibility because final users depend on what you do or won’t do.

… and maintaining a library for Kotlin Multiplatform is even harder

Maintaining an open source library is even harder, because you are providing the building blocks on which third party apps rely, so the exposure to end-users scales up exponentially, responsibilities are much greater and so is the amount of stress maintainers are subjected to.

Kotlin Multiplatform is highly dynamic and ever-evolving ecosystem, where maintaining a library is almost a nightmare: not only the underlying platforms behind each target evolve continuously and independently ‒ JVM, native (macOS / iOS / WatchOS / TvOS / Linux / Android / MinGW) Wasm, JavaScript ‒ but also each new release of the Kotlin compiler can break things, considering JetBrains hasn’t stabilized yet the APIs for compiler plugins, so each new version is potentially breaking compatibility.

Beyond the K2 compiler, the same is valid for KSP (Kotlin symbol processor) which has a release cycle close (but not 100% aligned) with the one of the compiler, with every new version potentially requiring adjustments.

Development previews and Release Candidates for both the compiler and the symbol processors are made available for the community before a new stable release becomes public, in order to give both app developers and library maintainers the time to test and adapt; nonetheless it should not be taken for granted that an open source project (especially if maintained by a small group of volunteers) do so, considering there may be other internal priorities when the new version of an external build tool is released.

Our experience at Procyon

An initial dilemma and a promised solution

With this in mind, let us consider what happened during the last weeks in our apps. Both the Raccoon apps are using Ktor for networking, due to its excellent flexibility and multiplatform support.

But I was used to Retrofit to write endpoint contracts and abstract away how network calls are performed. Using annotations to define service specifications and rely on code generation to create an implementation which internally calls an HTTP client is convenient and can save writing a considerable amount of boilerplate.

Unfortunately, Retrofit is not available on KMP, so there are two alternatives:

  1. use just the Ktor client, which has a nice DSL to configure the base HTTP client as well as each individual request, plus it offers support for authentication, content negotiation (with several serialization options), logging, etc.
  2. use a library like Ktorfit, which is very similar to Retrofit and offers a familiar set of annotations plus all the advantages of code generation.

I wanted to experiment, so in 2023 chose solution 2, and for the Lemmy app there were no issues using Ktorfit in the beginning.

The end of the honeymoon

When in 2024 I started working on the Friendica/Mastodon app, some headaches arrived because in some Mastodon APIs for pagination you need to access both the body and the headers of responses. Doing so requires method signatures to change in service definition (and you have to add an additional converter). Having to deal with Response<T> instead of T as a return type started to feel like the boilerplate I wanted to avoid, but I could use it just where it was needed, so overall it was fine.

When KSP 2 reached the stable stage and became the default in April 2025, both apps broke because implicit inference of dependencies between Gradle tasks (and both the Android and iOS compile tasks depended on kspCommonMainKotlinMetadata) changed. But, again, I adapted my setup after spending some time figuring out how to deal with this issue (not documented), and I still thought the benefits from using Ktorfit outnumbered the disadvantages.

The final breakup

The breakup arrived at the end of June 2025, when Kotlin 2.2.0 and KSP 2.2.0-2.0.2 were released. The library broke again, it was not possible to update the Kotlin Multiplatform plugin, which made it risky to upgrade the Gradle distribution and the Android Gradle Plugin (see here for more compatibility details). As if it wasn’t enough, I had recently adopted ViewModels from AndroidX lifecycle library, and an incompatibility between the version of the library available for KMP and the AGP version I was stuck on made the Android lint crash ( see here), so my CI pipelines were broken and I had to skip a beta release.

Someone had already filed an issue to Ktorfit maintainers, but the days passed and the fix, even if a contributor had submitted a solution already, was not being merged. People started asking for updates (which is understandable considering the amount of issues I found myself in too) and I took part in the discussion wondering whether this KSP release was the gravestone for the library and switching to plain Ktor (i.e. solution 1) would allow me to escape the impasse. If there were no plans to release a new version in the short term, which is understandable too because the team could have other priorities, it could be a viable option.

And here the hell started. A well known personality in the Compose and Kotlin world, who was not even a direct contributor of the project, replied to me

Quit complaining, and constantly asking for updates. If you want to write all of the service definitions yourself, then go ahead!

and then, when someone intervened to try and make the tones settle down a little bit, replied angrily

Are you paying for support? Are you paying for maintenance? I very much doubt it, therefore you have zero right to expect anything.

And yes, at that point enough was enough. I started working on this and this to completely remove Ktorfit from all Procyon projects. The result was quite neat:

  • with dependency injection, you still decouple the service clients and the service implementations;
  • Ktor has a nice DSL to configure request (both centrally and individually).

Considering the unwelcoming community around it, I don’t think I’ll revert the decision, use Ktorfit again in other projects, submit new report or collaborate with them in any way in the future.

Lessons learned

What lessons did I learn from all this? First of all, as already discussed multiple times here, that choosing wisely your libraries can really make the difference. And by “wisely” I do not only mean that they implement the features they are made for, but also that they are well-maintained, updated regularly and with a positive and supportive community around them. Codes of conduct for open source projects are there for a reason, we can do better than proprietary alternatives, we believe that community in itself is a value and our words / actions reflect this principle.

Secondly, I had to review my opinion on “very important people” in software development. One can have a high degree, a great career, be an active and renowned member of the open source movement and still behave rudely to others, scare away contributors, dismiss arrogantly bug reports, etc.

I still think highly of the person who argued with me: from a technical point of view he is on a level I probably will probably never reach. But we are humans, we have feelings, we already live in a harsh world and we should try to be kind to each other, especially with those who are not our enemies.

I think replying in that way to someone, without knowing anything of what they are going through IRL and without trying to understand the reasons of their behaviour, shows you have little empathy and — quoting what I’ve been told when I said I would switch away — «puts you in a bad light».