The Case Against Kotlin

Ryan Cooke | Android Engineer, Core Experience

It’s a big decision to start using Kotlin in your app. Right now, Kotlin may be nearing the “Peak of Inflated Expectations” in the Hype Cycle. You can find endless quality blogs, podcasts and videos on the virtues of Kotlin. For this post let’s assume you understand the benefits of it. Here we’ll look in-depth at the challenges Android developers will likely face with Kotlin and offer solutions. There are real costs to consider when adopting any new language, and Kotlin isn’t a fit for every team. We hope this article will be useful for teams seriously weighing the cost/benefit of Kotlin.

(*While this post looks at some of the challenges of adopting Kotlin, we enthusiastically use Kotlin at Pinterest. Check out our helpful tips to make the transition from Java, and stay tuned for additional posts from us on Kotlin.)

Kotlin on the Hype Curve

Problem: The learning curve

Objectively speaking Kotlin isn’t a popular language. It only recently made the top 50 most popular programming languages. If you’re going to use Kotlin in your code base, you’ll need to teach almost every developer on your team how to use it. It also needs to be maintained. Even if it loses popularity, you’ll need to continue training developers (who may not be interested in learning Kotlin).

So let’s talk about the learning curve. You’ll lose some developer velocity to the learning curve, and your onboarding process will likely be slowed. We’ve found it generally takes about about a week of actively working in Kotlin for a Java developer to feel comfortable. Developers need to learn Kotlin well enough to confidently read the language. While a few developers will self-teach themselves, teams will still need to set aside training time for everyone to get up to speed. New developers will need to learn Kotlin, and a one and done training won’t be enough. In addition, current developers who are trained but rarely touch Kotlin may need a refresher if they move to a part of the code requiring Kotlin. This means onboarding is slower and you may lose some velocity.

It’s important to understand that the initial week is all about becoming comfortable with Kotlin, and there will still be a lot of learning to do. Even the most experienced Kotlin developers are still learning tricks and ways to do things better, which the whole team then needs to learn. If your team doesn’t have Kotlin experts, then you’ll need to recognize that there’s no standard equivalent to Effective Java for determining best practices. If you decide to forge the best practices yourself, it can be time-consuming and tricky, but is necessary to have consistent approaches for solving similar problems.

Solution: The learning curve

The first solution is to just be aware. Adding Kotlin to your code base is betting on Kotlin’s longevity and continued growth. If that bet is right, then maintaining the code and learning will generally become less challenging. If the bet is wrong, then Kotlin will be tech debt. Google’s official support is solid evidence Kotlin is here to stay, but that support doesn’t always last forever.

There are a ton of resources for learning Kotlin such as Koans and great books. What we’ve found most effective is a single Kotlin advocate, mentoring and encouraging their immediate team.

Developer velocity was the initial selling point of Kotlin for me. When I realized very few developers actually saw the developer velocity gain, I was left with a bit of a, “so what’s the point” feeling. I expect that developer velocity gains will come when teams can require Kotlin experience and have dedicated Kotlin experts, and when stability is less of an issue. But we aren’t there yet.

Problem: Build time

Kotlin will make your build times worse. We have pretty respectable Gradle build times at just over 30 seconds for incremental and around 75 seconds for clean builds. Kotlin accounts for about 25 percent of our clean build time and 40 percent of our incremental build time.

Solution: Build time

Deal with it.

Errr… more usefully, we tested a side project’s build time, comparing it before and after Kotlin. We found that the majority of our build time loss came from converting one Kotlin file. For clean builds, we continue to see the builds slow as we’ve converted more files to Kotlin (but that additional slowdown wasn’t huge).

The good news is beyond the initial addition of Kotlin, incremental and no-change build times remained constant regardless of how many files were converted. You can get a fairly good sense of what build times will be by converting one file. We use the Gradle-Profiler for profiling, which provides us with an accurate, objective build time projection.

Problem: Development stability

On our team people who disliked Kotlin didn’t dislike it because lambdas scared them, or because they’d rather wait to see if the app crashes to figure out proper null handling or even because var and val look similar. The simplest reason for a non-Kotlin developer to dislike it is when there’s an issue preventing them from writing code and being productive.

This has happened to us multiple times and could easily happen to you. For example, we’ve had issues where incremental builds don’t work for some developers. We’ve had other issues where things like changing branches would always require a clean build. We’ve had builds randomly fail because kapt (Kotlin Annotation Processor Tool) would sometimes get out of memory errors. Additionally, Kotlin doesn’t play nicely with instant apps, and we’ve seen an increase in Android Studio crashes when the Kotlin plugin is enabled. In terms of development, just when you think everything is stable, another problem can pop up.

Because Kotlin and kapt are tools most developers aren’t familiar, it can lead to significant time lost to red herrings that weren’t actually Kotlin’s fault. For example, we’d see an issue such as a developer missing an import statement and the build failed showing a lot of kapt errors. Not being familiar with Kotlin, the developer immediately assumed Kotlin was causing the problem and lost time investigating what was a simple fix. This “weirdness” combined with the actual stability issues means there’s significant maintenance time lost.

Solution: Development stability

The best solution is to make everything stable and then cautiously upgrade. Kotlin, Gradle, Android Studio and everything else will get to a state where they work well together, but it frequently takes a few releases. This is difficult if you want to use the newest Android Studio or something similar. If you decide to upgrade aggressively, you can file bugs for the issues you experience, and the teams are quite responsive and eager to fix any issue. If you don’t want deal with bugs, upgrade patiently and stick with the stable builds.

Problem: Static analysis

Java is a mature language and has many great static analysis tools that alert you of issues. This means the human reviewer doesn’t need to check whether code follows rules and conventions. Existing tools like FindBugs, PMD, Error Prone, Checkstyles and Lint are great. Developers generally want to avoid doing things that cause problems, but we realize that expecting everyone to remember everything, tell new hires and check every code review for these tiny gotchas is just not sustainable. After all, we aren’t machines, and that’s why we give machines rules to fail our build if we miss a best practice or fall for a gotcha. There’s a lot more room for developers to make mistakes without static analysis tools.

Solution: Static analysis

This is a wait and see kind of problem. My understanding is that Lint rules and inspects should work in Kotlin on Android Studio 3.0. For instance, we recently tested the “remove all unused resources” inspections in the Canary Android Studio release, and the inspection removed resources that were being used by Kotlin, so the tools aren’t there quite yet. If you’re a real hero, you can join the cause and start working on your own static analyzers or compatibility approaches.

To (somewhat) balance out the lack of static analysis, major Kotlin features like null handling reduce a potential problem the code reviewer and developer need to think about.

Problem: Reversibility

Reversibility is the ability to easily undo a change or decision. Kotlin is deceptively not reversible. While it’s easy to convert a Java file to Kotlin, the best approach for converting from Kotlin to Java is to look at the Kotlin bytecode, decompile and then fix oddities. You could also simply rewrite the file. Decompiling won’t result in code that matches your team’s code quality standards. If it does, you may want to reevaluate your naming expectations.

Decompiled data class. Not production quality Java.

Let’s look at an example of what can happen. Say you have five engineers looking to learn and evaluate Kotlin, and each converts five files and then adds another five files. Now there are 50 Kotlin files, even before you’ve decided this language is for you. If you decide against Kotlin, you’ll spend a lot of time tediously converting files back, especially if the converted ones changed enough for version control to not be useful. If you used Anko or another similar Kotlin library, or even advanced Kotlin functionality, that’s another layer of complexity to the reversion.

Down the road, if Kotlin starts causing a problem, you’ll have to solve the problem, no matter how difficult or development-blocking. It won’t be an option to remove Kotlin from the code base.

Solution: Reversibility

Reversibility is a must to keep in mind when evaluating Kotlin. It’s easy to add, but you should ensure you’re not using Kotlin only because it’s too difficult to remove. Changing fairly simple/rewritable code, such as test code, is always a good place to start when evaluating a new technology. If you do start converting app files, convert well unit tested files. Unit tests will give you the confidence to make significant changes to the file while still knowing you haven’t broken anything. They also make changing back to Java easier. Beyond that, be aware of how difficult it could be to revert the decision.

Conclusion

Learning curve, build times, development stability and static analysis will all get better. Google is officially supporting the language which is a sign things will rapidly get better. If you want to wait until they’re better, that’s not crazy. It is never too late to add Kotlin to your code base, but it can be too late to remove it.

We use Kotlin at Pinterest, but we do so knowing and living the growing pains of the language. This post purposely focuses on the risks you should consider, but a lot of these problems will become less of burden in time.

Please share considerations we may have missed, or counterpoints in the comments. If you want to talk more on Kotlin send us a line! If you’re in San Francisco we host periodic Android-Knit lunches at our office where teams around the city talk Android. We’d love to host you!

Also, we are hiring!