The golden age of Kotlin and its uncertain future
In my 10+ years as a software engineer at Infobip, much, if not most, of my time was dedicated to maintaining code. More often than not, it was someone else’s code.
I had the fortune, or bad luck depending on how you view it, of seeing different pieces of technology explode and implode, never to be used again on newer projects.
One such occasion happened back in 2014. The team that created and maintained one product at Infobip fell apart, and it fell upon my team to take over and maintain it. It had all the latest bells and whistles – node.js, Cassandra, MongoDB, Redis, MSSQL, Groovy, Grails, ELK, and so on. It doesn’t really matter who, how and why chose all those technologies. The only thing important was that the complexity budget was insane.
Complexity killed the project
It took my original team over a month just to set up everything locally to be able to start the project and try things out. Pretty soon, I was transferred to a different team, where I was tasked with building a proof of concept, an MVP product that does the same thing as the one we were supposed to maintain but with a minimum set of technologies.
We built it like we built most of the stuff at Infobip. With plain old boring Java and MSSQL and… that’s about it. That was back in 2015, and this service still lives today in 2023. The complexity of the original project killed it. Worse yet, it killed the team that was supposed to maintain it as well.
The moral of the story is – you need to be extra careful about your complexity budget. It’s not just about the number of services or libraries you maintain; it’s also about the number of various technologies you need to maintain and the future perspective of a piece of technology.
When Groovy was groovy
In 2013, one of the hottest languages on JVM was not Java but Groovy. It had lambdas, dynamic structures, named parameter constructors, a popular Grails framework, and so on. But then, in 2014, as if no one could’ve predicted it, Java 8 was released with a new hot feature – lambdas.
Lambdas eliminated one of the most significant negative remarks about Java at the time – a huge ceremony of anonymous inner classes for passing behavior around in code. Or, as it was colloquially said – Java doesn’t have lambdas. Not long after, around 2015/2016, there was a significant decline and fall of Groovy. Today, its use has significantly declined and no one even thinks of using it when creating new services.
But the innovation in the JVM ecosystem didn’t decline with Groovy, quite the contrary. The next shiny hot new thing was Scala!
Does anyone remember Scala?
I do! I even completed a Coursera course named ‘Functional Programming Principles in Scala’ held by its author, Martin Odersky. Honestly, I was more enchanted by Scala than by Groovy’s features. The biggest one I was lacking in Java was pattern matching. Navigating through complex data structures without (ab)use of the visitor pattern with simple lambda-like expressions.
There were some Infobip services written in Scala, but it never took off. The downfall began around 2017 when one of the key maintainers of the language left.
The arrival of Kotlin
The next contender that would ‘kill Java’ was Kotlin. It slowly took off but for me, it started really taking off around 2017, first when our People product was created – the backend was written in Kotlin and then when our default Maven parent was enhanced with Kotlin support. The first one was important as the first large-scale Infobip deployment that used Kotlin, and the second one was the mark of the beginning of en masse adoption.
Kotlin pros
- Java code interoperability
While it’s not perfect, Kotlin has better Java code interoperability than its predecessors. Most likely because it came after and could learn from the experiences and pitfalls of the likes of Groovy and Scala.
It also doesn’t require any specialized build tools (like sbt for Scala) and has plugins and integration with IntelliJ. The fact that it’s created by the most popular Java IDE creator, JetBrains is a big pro, but that has one red flag I’ll share later in the con list.
Coroutines
This one is actually big in the Infobip software ecosystem. It enables a syntax-wise cheap solution to the scaling problem of async tasking. Especially compared to RxJava, Reactor, CompletableFutures, etc.
Until Java 21 came out, Java didn’t have a contender for this feature, but with the release of 21 and Virtual Threads, it has it. Next year will be critical to determine how it stacks up.
If Virtual Threads stack up well and diminish the value of switching to Kotlin for coroutines, it will mark the beginning of the decline of Kotlin. Especially if JetBrains doesn’t come up with a big new hot feature that brings a lot of value.
- Data structure and pattern matching
Before records (16) and pattern matching (21), Lombok was the only alternative in Java.
I dislike Lombok more than the average Java developer, especially since it breaks the first rule of annotation processing in Java – annotation processors shouldn’t modify .classes generated by the Java compiler.
However, with records, I believe this to be a better and better long-term solution than what Kotlin provides – especially given the plans somewhat explained in this Java language update (for full context, I suggest watching the whole video).
Java 21 pattern matching has type patterns and exhaustiveness, so this is one pro that Kotlin no longer has.
- Null handling
Null was always a pitfall in Java. It has slightly improved with the controversial Optional type. It’s also why I suggest that everyone use only wrapper types everywhere, instead of primitives, unless they can prove with a JMH test that a primitive provides enough of a performance benefit.
Kotlin has so-called Elvis operator support that is quite popular in modern language design choice for null handling. It’s better than not having anything at all, but it can appear quite unergonomic and wonky with its interactions with the language type system. I prefer the general monad approach with a widely established map and flat map conventions over sprinkling your code with ?s .
The biggest disadvantage of Optional in Java is not its syntax overhead but the controversy around it, whether one should use it all. Initially, it was created almost exclusively for Java 8 Streams, and the “no one else should use it” mantra by JDK maintainers was really damaging. Lately, more and more people on Oracle’s payroll have gone into the open and said that you can and should use Optional everywhere instead of risking NPEs, with the prime example being here.
My take is they didn’t want huge adoption and implementations in the wild that use Optional<?> types as a store of three possible sets of values (null, Optional.of, and Optional.empty) so that the whole Valhalla value objects project has an easier way of dealing with making Optional an inline type that doesn’t allow nulls (this would break all the code that uses Optional as mentioned before). It is easier than potentially breaking code in the wild and insisting they didn’t adhere to the Javadoc of Optional.
- Other features
Other features in Kotlin, like language syntax and method extensions, are not worth mentioning. Bringing features to the language just to bring features can be quite harmful. The biggest red flag example comes from another language mentioned earlier, Scala, which, like C++, provides an option to overload operators on types. Things like that make the code really hard to maintain when you can no longer safely assume that an operator does what you expect it to do.
The best next-in-line example is extension methods. In a corporation where it’s expected that each team consists of mostly juniors, then mids, and then seniors, it is really dangerous. It can lead to a lot of bad code littered with traps for the uninitiated. One more thing on that note – if you expect anyone to pass a ritual of the initiation to be able to maintain a piece of code – you’re not behaving like a software engineer. Quite the contrary – you’re breaking the ethics of software engineering! Code must be maintainable, and that is the prime directive.
Kotlin cons
- Java code interoperability
How can the first pro also be a con, you ask? Well, here is the official blog post that paints the picture pretty clearly. To quote:
The next thing is straightforward: we expect Kotlin to drive the sales of IntelliJ IDEA.
Now you can imagine why IntelliJ IDEA, after all those years, has the action to convert Java to Kotlin but not to convert Kotlin to Java. That’s the usual practice of vendors locking in and extracting bigger margins – something that became popular again in 2023. But I digress.
- Kotlin ecosystem
Kotlin ecosystem is severely lacking compared to Java. FAANG has first-class support and commitments to Java, like providing JDK with multi-year support commitments.
- Workforce
To this day, there are significantly fewer Kotlin developers than Java developers.
What does that mean for companies using Kotlin? More expensive workforce and blockers in finding people to work on projects. They can choose to wait until someone shows up on the market, or they can start onboarding their Java developers to Kotlin. Both of those choices cost money.
- Lack of progress
Compared to Java lately (e.g., records two years ago, pattern matching, and VT release this year), Kotlin has been stagnating in delivering the big features that would bring us (Infobip) value over alternatives. That is, for me, the biggest concern about Kotlin that dwarfs all others mentioned so far.
Playing the devil’s advocate
The fact remains that we need Kotlin. Why? To help us research, innovate, and challenge the status quo.
If Kotlin continues to stagnate and no new big contender shows up with hot new features that increase our efficiency in delivery, this will be a problem. For a company with half of its infrastructure, if not more, written in Java and working only in JVM, jumping to alternatives like Kotlin is much cheaper than Rust or Go. We need options and shouldn’t put all our eggs in one basket.
The grim future
To finish this blog post, here’s what the title is about. At Infobip, it has been the golden age of Kotlin since 2017 until today. Whether it continues depends entirely on JetBrains and their ability to innovate Kotlin. The critical moment is going to be 2025.
Why 2025? At that point, we will see more features coming to Java (e.g., Valhalla and Panama projects) with no Kotlin alternatives. If Kotlin doesn’t make a significant move by then, its popularity will decline and reach a critical point. You can already see the sentiment moving in that direction in developer communities on YouTube, Hacker News, or Reddit, but it’s not critical yet.