The original purpose of this paper was to help drive the consideration to introduce Kotlin at Intuit. The current version is a slight variation of the paper featuring me and Katie Levy’s opinions and observations and why we think Kotlin has helped increase our developer productivity velocity.
Most engineers developing server-side capabilities or Android applications use Java. Java is an established, well-understood language that has been in existence for over two decades. At Intuit specifically, most teams work in Java.
Kotlin is a statically typed programming language that can run on the Java Virtual Machine. It is interoperable with Java and Google has named it one of the official languages of Android. This paper provides a recommendation for development teams to adopt Kotlin and explains why some of these Kotlin features will improve Intuit’s current Java development, reducing overhead cognitive burden, which will allow developers to focus on creating value for customers.
Common pitfalls in Java include null references, boilerplate code, and mutability due to the way that the language has been developed. Java allows the creation of variables that are nullable by default. This encourages mutation throughout code, and in result causes defects and bugs, slowing down developer productivity, and taking time away from developers focusing on delivering business needs. Kotlin can help with these problems. It has a lot of features that can help improve the way we develop today. Some features built into the Kotlin language are inline functions, property delegation, extension functions, default and named arguments, null safety, data classes, and sealed classes. These features are not all natively available in Java and would be difficult to reproduce.
Intuit teams integrate Kotlin into their Java applications for server-side development (mostly backend of web applications) and Android development to increase developer productivity, decrease defects and bugs in code, and attract and retain top talent by using the industry’s best technology.
In the following sections, we will dive into some useful features of Kotlin that encourage best coding practices, talk about the benefits we have already seen as we have added Kotlin into our everyday development, and show some examples of the simplicity in integrating Kotlin into current applications. Finally, we will provide a recommendation of next steps for taking action on the vision outlined in this paper.
Kotlin language features
Using Kotlin will decrease defects and bugs in code because of its ability to handle null values. Everyone knows the java null pointer exception at runtime, known as the “Billion Dollar Mistake”. Java code does not know that there is going to be a null value when you compile since everything can be null by default. Below is an image from the OverOps Blog showing the top 10 exceptions in Java, NullPointerException being the top one.
Kotlin has a built-in feature in the language where variables are non-nullable by default which can eliminate this exception. This forces the developer to consciously set the variable to nullable when declaring the variable. Then, if a non-nullable variable is set to null in the code, a compile-time exception will be thrown in comparison the comparable runtime exception that Java would throw. This encourages the developer to clearly understand what value the variable is defining and whether it should ever be null. When developing in Java, variables are nullable by default which allows engineers to make decisions without really understanding why something is allowed to be nullable, causing many null pointer exceptions. Regarding the support of non-nullable variables in Java, there is a possibility to do this using third-party plugins, such as Lombok. Kotlin provides first party support instead of using plugins. This provides more reliable support and in certain cases, reduces the bundle size of apps as well.
Kotlin needs to be able to work seamlessly with Java in order for companies (or existing applications) to adopt Kotlin. In order for Intuit to fully accept and approve using Kotlin, no legacy code needs to change. Kotlin can be called from Java code and Java can be called from Kotlin code. In Kotlin everything can explicitly be declared nullable and mutable to allow easy interoperability with legacy Java code. When writing new Kotlin code to work with old Java code, the questions that should always be asked are, “Why does it need to be nullable?” and “Why does it need to be mutable?”
Skill Set required
One of Intuit’s internal products is a Spring Boot web application and Kotlin’s ease with integration into this project proves the simplicity of this process. A new feature that involved interaction with a database, a downstream service call, and some data manipulation was developed as a Proof of Concept for Kotlin in an existing Java Spring Boot project. A Software Engineer I, who had never used Kotlin before, integrated Kotlin into the internal product, developed, tested, and deployed this entire feature in three days. Ever since this has been deployed, there have been many other services and features written in Kotlin. Each feature has the same amount of unit test coverage as the Java code and integration tests written in karate (https://github.com/intuit/karate). The features that have been developed in Kotlin have fewer files due to the simplicity of being able to define multiple data transfer objects in the same file. Seeing them side by side in the same file without the boilerplate getters and setters allow for efficient analysis. The Kotlin documentation website states that there are many advantages to use Kotlin over Java. Specifically the website states, “approximately a 40% cut in the number of lines of code.” lines of code alone isn’t the best metric to measure advantages but the fact that there are fewer bugs due to fewer chances for error is a valid metric proven to be true on this internal product.
Tools and Infrastructure Support, Java vs Kotlin
Kotlin language designers prioritized seamless integration with already existing Java tools when developing the language. The majority of the current tools we use today to develop at Intuit can be used with Kotlin, including Maven and Gradle. Furthermore, Gradle 5 will allow you to write the gradle file in Kotlin instead of Groovy. Many applications have separate Kotlin Source Directory so that we can organize all new Kotlin functionality into that directory. The changes in a maven application’s pom.xml configuration are below, the important thing to note is that Kotlin needs to compile before Java.
The changes to a Gradle project are below:
Since Kotlin is a runtime library, the Jenkins build process for current applications can remain the same. Jacoco Code Coverage reports coverage on Kotlin files and Kotlin tests in our regular coverage reports on our PR builds. Additionally, there is an easy interpolation between Java and Kotlin in terms of testing as well as Java code can be tested with Kotlin tests or Kotlin code can be tested with Java tests. There is no additional plugin or tool needed for Jacoco coverage reporting to work in our existing web applications and Android applications. Kotlin also integrates seamlessly with the testing frameworks, Junit with Mockito, used for unit testing our applications.
Spring Boot && Kotlin
The internal product that we mentioned earlier is a Spring Boot web application that has Kotlin integrated into it. The Spring Boot team has done significant work to ensure easy integration with Kotlin. Specifically in the internal product, there were no issues as the team integrated Kotlin. The Kotlin documentation states that the steps and instructions found on the Spring Guides(https://spring.io/guides) can be followed verbatim with Kotlin. The only minor difference is when defining the project structure for source folders in Gradle or Maven. The Kotlin source folder needs to be listed first for Kotlin code to be compiled first. Otherwise, the same annotations used for Spring Boot in Java can be used for Kotlin.
Defining Data Classes and Controllers in Kotlin are a one-to-one translation from Java and Spring Boot. The example on the Kotlin documentation shows this well. Using the example of defining a Greeting Data Class and Controller. The Data Class that has two properties: id and a content.
Next, a GreetingController will be used for a get request:
When creating the Application class Spring Boot looks for a public static main method. This can be defined in Kotlin using a top-level function defined outside Application class like this:
Android && Kotlin
Google heavily encourages the Kotlin language as it promotes a more healthy and performant application. More importantly, Google has declared Kotlin as one of the three official languages of Android development. There are many sample applications and learning materials created by Google as the company shows Android documentation first in Kotlin, and secondly in Java. Google also created a library, called Android KTX, to optimize Kotlin usage specifically in Android applications as part of their Jetpack collection. Intuit’s Android applications seamlessly integrated Kotlin into their already existing Java codebases. The Kotlin runtime dependency was added through Gradle and the build pipeline on Jenkins was not affected. The diagram below shows the build process for a project with Kotlin.
Strong tooling support in the development environment, Android Studio, allows for faster adoption and understanding of the language. The IDE even has a tool to auto-convert Java files to Kotlin and auto-convert Java code to Kotlin code when pasted into a Kotlin class. Other features in Android Studio include autocomplete, lint checking, refactoring, debugging, and code coverage for Kotlin. Currently, our Android applications are using Kotlin in their new features which has reduced the amount of boilerplate code significantly. For example, a data model file was reduced from 114 lines in Java to only 8 lines of code in Kotlin. This saves engineers’ time writing the code, later reading the code. Furthermore, Kotlin minimizes the risk of error by handling common patterns behind the scenes through its helpful constructs such as data classes. Furthermore, new features written fully in Kotlin, have significantly reduced the number of crashes during their use, mostly to the benefit of Kotlin’s null-safety feature. Intuit’s Open Source Android Library, Truffle-Shuffle, is written fully in Kotlin uses data class in Truffle-Shuffle, CardMeasurements.kt, uses the data class construct to conveniently remove getters and setters from the Kotlin source code. Truffle-Shuffle takes advantage of many of the language’s features such as functional programming constructs, named arguments, null safety, default parameters, smart casts and more.
Functional Programming && Kotlin
Kotlin can be written with first-class functions, meaning functions represent values. Those values can be stored in variables, passed as parameters, or returned from other functions. Other functional programming concepts that Kotlin helps enforce are immutability and the elimination of side effects. Immutability means that state will not change after creation and no side effects means that inside functions, the state of objects will not be modified or interact with anything outside those functions. Kotlin helps enforce immutability with a few features. For example, when declaring variables, val or var can be used. Var declares the variable as mutable, however, val declares the variable as immutable. Also, Kotlin emphasizes expression-based coding where code is evaluated to a value, instead of statement-based coding where code is executed to perform some action. An if expression in Kotlin is an example of this. An if expression returns a value that you can set to a variable or return right away. Another expression in Kotlin that helps drive functional programming and decrease bugs is a when expression and specifically using a when expression with sealed classes or enums. Since the compiler can prove that all possible cases are covered within the when expression, there is no need for an else branch. An example of this is shown below:
Easily Testable Code
These functional programming concepts can be achieved in Java with libraries like Vavr, formerly known as Javaslang, that provide persistent data types and functional control structures. Kotlin has the benefits of Javaslang built into the language providing first party support instead of third party. Kotlin is a great transition for engineers who are learning functional programming. The Software Engineer 1 and intern working on one of Intuit’s internal products have been able to learn Kotlin and specifically functional programming in Kotlin in a few days and have expressed that it has been easier to grasp functional programming concepts within Kotlin than it has been in Java without using plugins.
As stated before, one of our internal tools uses Junit with Mockito for unit testing in Java and Kotlin tests are written using the same frameworks. Testing in Kotlin is simpler then unit testing in Java for a few reasons. The ability to use default values and named arguments allow for simple construction of different response objects for testing. Often times in unit tests, the same method is called multiple times with a difference in one or two parameters. Named arguments eliminate the need to pass in extra values, often times just set to null in Java. Default arguments can be used to write one method instead of overloading methods multiple times in Java. Named arguments eliminate bugs when testing due to the wrong order of parameters. These improvements in testing will improve test quality and efficiency.
Next steps – how to learn more and get started:
We recommend introducing Kotlin to your company through providing training and resources to increase the technical expertise. At Intuit, we have found group coding exercises to be effective in sharing knowledge to a large number of people. Then, engineers can start practicing their Kotlin skills on their own through test files, data classes, and the development of new features. They can use the tools in IntelliJ and Android Studio to auto convert Java code to Kotlin and dig into the Kotlin standard library source code to better understand the functionality. Over time, code reviews and practice will improve the quality of the code and thus, the quality of your product.
We also recommend considering Kotlin as an enhancement to Java. In other words, it would be nice to convert a whole application to Kotlin, but that might not be the most realistic decision if there are other product priorities for the business. We have found that building new features in Kotlin and refactoring some low quality features to Kotlin has been a more reasonable transition to Kotlin as the language interoperability allows the two languages to coexist.
The Kotlin community is continuously growing and there are many ways to get involved! Reach out with any comments or feedback about your own experiences with Kotlin and introducing new technology to your companies. Below are some of the best resources we have used throughout our journey.
- Kotlin documentation – https://kotlinlang.org/
- Exercises – https://try.kotlinlang.org
- KotlinConf 2018 Talks on YouTube – https://www.youtube.com/playlist?list=PLQ176FUIyIUbVvFMqDc2jhxS-t562uytr
- Kotlin in Action by Svetlana Isakova, Dmitry Jemerov (https://www.safaribooksonline.com/library/view/kotlin-in-action/ )
- Slack: #kotlinlang
- TalkingKotlin Podcast with Shelby Cohen – http://talkingkotlin.com/adopting-kotlin-and-functional-programming/
- Truffle Shuffle by Katie Levy – https://github.com/intuit/truffle-shuffle
- Top Exceptions by Types: https://blog.takipi.com/the-top-10-exceptions-types-in-production-java-applications-based-on-1b-events/
- Creating a RESTful Web Service with Spring Boot: https://kotlinlang.org/docs/tutorials/spring-boot-restful.html