Embracing Kotlin

Joel Denke
Avanza Tech

--

Spring 2017 was the beginning of something big without any of us actually knowing it. We took the large decision to go all-in for Kotlin at Avanza in our Android app. Today we are 100 % Kotlin, even including unit and Espresso tests. In the end some converted packages saved us up to 50 % lines of code, compared to earlier Java code. The biggest changes were in our API models. The best part, it only took about 2 weeks. Now you ask, how is that even possible?

Kotlin becomes a first-class language on Android

Kotlin is a programming language developed by JetBrains, unveiled summer 2011. The large Big Bang for Kotlin and Android was at Google I/O 2017, when Google presented first-class support for Kotlin on Android. That increased our confidence in earlier decision to go Kotlin all the way.

The key to migrating a large code base is doing one part at a time

I must be honest though, I did not understand the actual power of Kotlin until I got the leading role in migrating the whole app from Java. And I certainly did not think it would become my favourite language. The best part, JetBrains had powerful support for Kotlin in IntelliJ with the magic auto convert tool, from Java to Kotlin. As a first approach we selected the whole project and let the tool work for us by converting everything by itself. However, it was not that easy. The converter made some major mistakes and in some cases the code did not even compile. We are quite heavy users of RxJava and lambdas, which were among the most common things that failed auto converting. Seeing the amount of compiler errors, we decided to begin from scratch and try to find another way.

The next approach, which turned out to be successful in the end, was to go one package at a time. To be able to parallelize the work and convert packages simultaneously, the converting was initially split into separate tasks which isolated each package into blocks. The first days me and my colleague were successfully converting code at the same time. One of the key parts here is that Kotlin is two-way-compatible with Java. The convert tool helped us learn how to write Kotlin code that seamlessly interoperated with Java. Because of that fact, we could migrate one part to Kotlin and still have working Java code interoperating with that code.

The hardest part is to glue our code in Kotlin with external dependencies

As previously mentioned, the convert tool is far from bulletproof when converting Java to Kotlin. We are avid users of libraries such as Retrolambda, RxJava, AutoValue, ButterKnife etc to simplify complex operations and reduce boilerplate. The parts of our code that used these libraries heavily were actually the parts that most often failed to convert automatically.

One of the biggest challenges was to make our API models behave exactly the same as in Java. Kotlin provides data classes which among other things auto-generate equals and hashCode methods. Since we previously used AutoValue in our API models, we could replace it with data classes completely. Data classes is also handy when writing unit tests, with named arguments and default values for methods. Did I mention you do not need any more getters and setters in Kotlin as well?

The fastest way was to migrate all of our API models to data classes manually. The problem, Kotlin is not allowing static methods used by Parceable interface. And because all fields are default public and immutable in Kotlin, it made it harder. The solution was to switch to PaperParceable which were the most compatible library with Kotlin at the time. Today I would have chosen Parcelize, which is built in for Android from Kotlin version 1.1.4, in experimental state. A common issue experienced for many third party integration in the Kotlin migration, is everything default public and immutable in Kotlin. However it is also one of the best parts in Kotlin once having it in place.

As mentioned with Parceable and PaperParcel, static methods made the migration complicated. To solve the problem, the annotation JvmField comes to a rescue. It makes Kotlin properties behave like fields in Java. By using it, you explicitly allow Kotlin to let the visibility of the field be the same as the underlying property. This can also be used to solve Espresso, Dagger, Butterknife, Companion methods being compatible with interop calls from Java. Example of a data class combined with PaperParceable:

@PaperParcel
data class Headline(
val type: String?,
val title: String?,
val vignette: String?,
val source: String?,
val publishDate: DateTime,
val path: String
) : PaperParcelable {
companion object {
@JvmField val CREATOR = PaperParcelHeadline.CREATOR
}
}

The invisible parts above are generated hashCode and equals methods, Parcelable interface, getters/setters for each data class attribute. There is no need to use the Nullable or NonNull annotations to specify nullability in Kotlin. Specifying nullability is built in and required by design, using a question mark. You will get runtime errors if you require a value being non null, but an external dependency sends a null value when not expected to. To solve those parts, many values need to be nullable even if you don’t expect them to be. Documentation sometimes give misleading information about nullability, but the good news is more and more libraries are moving from Java to Kotlin.

More focus on innovation and less boilerplate

When we reached the point where we no longer had any restrictions using Java code co-op with Kotlin code, you can discard all concepts of statics, builders, factories, utils, nullability inconsistency and so forth. As a bonus Kotlin provides “magic” parts like extensions, coroutines, higher order functions, property delegates, smart casting and the list goes on. One example of an extension of BigDecimal could be:

fun BigDecimal.equalsIgnoreScale(other: BigDecimal?): Boolean =
other?.let { compareTo(it) == 0 } ?: false

In the end we actually got rid of up to 50 % code in our API models just by using data classes. I would classify the migration of just that part itself a huge victory for us. Our code now has a much higher consistency in type safety, thread safety, and proper nullability. The best part of Kotlin, I would say, is it makes coding much more fun by allowing us to focus more on innovation and writing less boilerplate. And for the Android platform, we can create more with less code and feel safe by reducing the amount of bugs.

Coding Kotlin is fun

These were just some of the highlights of Kotlin and our journey in migrating from Java. There is a lot more under the hood and I could probably continue writing this article forever. Maybe you will see more power of Kotlin in the future.

This journey made me embrace Kotlin in a way I would not have imagined. I honestly feel it is the most fun and beautiful language I’ve ever written code in. The obstacles and boring parts of Java are gone. We’ve increased the amount of fun and productivity for each Android developer at Avanza. The amount of bugs is reduced and it’s easier to find the bugs as well, spending less time debugging. Personally I would also say it will increase the amount of new features and much higher velocity for our Android app. At the end, in terms of fun and stability, I think both developers and our end users benefit from Kotlin.

--

--