Random Thoughts on Using Gradle With Kotlin DSL
Since Gradle 3.0 you can write your build scripts using Kotlin instead of Groovy. I was curious, so I decided to give it a try. Here are my thoughts on the process.
Why?
Ok, we can write our build scripts in Kotlin, but you might be wondering: ”why would I want to do that?” Here are my reasons:
1. All things Kotlin
Our backend codebase is mostly written in Kotlin. We even wrote our githooks using Kotlin scripts! So it was only natural to use Kotlin on our build tools too.
Being able to use the same language across the stack means that your learning efforts pays double. This way the team doesn’t have to learn a new language just to write a simple Gradle task. And as an added bonus you can apply the same testing, coverage and code inspection tools that you use in production to your tooling code.
2. IDE support
The second reason for making the transition was IDE support. Groovy is a dynamically typed language, which makes it harder for the IDE to provide accurate code completion and script validity through type checks. Kotlin being statically typed doesn’t suffer from the same problems
3. Interoperability
As you probably know Kotlin was designed with Java interoperability in mind. And the same interoperability extends to Groovy code.
This interoperability let us call Groovy code from Kotlin and viceversa. Which effectively means that you can have a mix of both Groovy and Kotlin scripts working together in the same project. So no need to migrate all your build scripts at once, or to push stubborn “Wally” to learn Kotlin DSL.
The exodus
”So how painful was the migration?” It wasn’t that bad really. Kotlin DSL was designed to be pretty similar to the classic build.gradle
files.
You’ll just have to push through that first moment when nothing seems to be working, your project doesn’t compile at all, and you know you’re a ⌘ + Z
away from a pristine working copy. But you can’t make an omelet without breaking a few eggs, can you?
I just wish there was some kind of automatic migration action in IntelliJ. Even if it’s a best effort that leaves you half way there, I’d greatly appreciate it. Ideally it should work just like when you paste some Java code into a Kotlin file: ⌘ + V
+ ✨fairy dust✨ and you have your build.gradle.kts
ready to go.
Resources
This are the resources that help me complete the migration. Hopefully you’ll find them helpful too.
- Official Gradle migration guide Start here! You don’t have to cover the whole thing but you can skim through it and later go back to the section you need.
- Samples in the Kotlin DSL repo This is the go-to place for Kotlin DSL samples. You’ll find yourself coming back to this repo over and over. Be sure to search the Issues section too.
- For the times when the Kotlin DSL repo doesn’t have what you’re looking for, I find it useful to use Github Search looking for code in files with
*.kts
extension. - jnizet/gradle-kotlin-dsl-migration-guide this is another migration guide that has proven useful in the past.
- Finally I followed this article by Handstand Sam to do dependency management on out multi-module project.
The not so good
1. “I can’t just copy-past things from Stack Overflow”
This is by far the biggest drawback. In my experience most teams have one or two ”build tool experts”. The rest of the team just use a few tasks and maybe add a dependency every now and then. This casual user might have a harder time using Kotlin DSL because copy-pasting pieces of code from the web will not work out of the box. Converting this snippets to Kotlin DSL is not rocket-science, but in some cases it might require some basic level of understanding of how Kotlin DSL works.
This is specially true when using plugins that were not designed with Kotlin DSL in mind (I’m looking at you protobuf Gradle plugin).
2. IDE support could be better
Remember all the nice things I said about IDE auto-completion on the build scripts? Well let me clarify: “IDE support is awesome… most of the time”.
Once you have your script fully migrated and IntelliJ has finished indexing then everything should work just fine. But to get there you’ll have to have your full build.gradle
script fully migrated. That’s why my advice is to comment everything out and start migrating piece by piece. For example you can start with configuring the repositories, and plugins and only then move to dependencies.
This gets intensified if you are working on a multi-module project and/or you’re using buildSrc
for custom plugins.
The silver lining is that IDE support is getting better with each release, and once you’ve migrated everything it mostly works.