loading...
Cover image for Why I went back to the Gradle Groovy DSL

Why I went back to the Gradle Groovy DSL

msfjarvis profile image Harsh Shandilya Originally published at msfjarvis.website ・2 min read

About an year ago when I first discovered the Gradle Kotlin DSL, I was very quick to jump on that train. Now it feels like a mistake.

The initial premise of the Gradle Kotlin DSL was very cool. You get first class code completion in the IDE, and you get to write Kotlin rather than the arguably weird Groovy. People were excited to finally be able to write complex build logic using the buildSrc functionality that this change introduced.

However the dream slowly started fading as more and more people started using the Kotlin DSL and the shortcomings became more apparent. My grievances with the Kotlin DSL are multifold as I'll detail below.

Just a disclaimer, This post is not meant to completely trash the Kotlin DSL's usability. It has it's own very great benefits and people who leverage those should continue using it and disregard this post :-)

Build times

The Gradle Kotlin DSL inflates build times significantly. Compiling buildSrc and all the *.gradle.kts files for my app takes upto 10 seconds longer than the Groovy DSL. Couple that with the fact that changing any file from buildSrc invalidated the entire compiler cache for me made iterative development extremely painful.

Half-baked API surface

Gradle doesn't seem to have invested any actual time in converting the original Groovy APIs into Kotlin-friendly versions before they peddled the Kotlin DSL to us. Check the samples below and decide for yourself.

Groovy

android {
  compileSdkVersion 29
  buildToolsVersion = '29.0.2'
  defaultConfig {
    minSdkVersion 21
    targetSdkVersion 29
  }
  buildTypes {
    minifyEnabled = true
  }
}

dependencies {
  implementation('my.company:fancy.library:1.1.1') {
    force = true
  }
}

Kotlin

android {
  compileSdkVersion(29)
  buildToolsVersion = "29.0.2"
  defaultConfig {
    minSdkVersion(21)
    targetSdkVersion(29)
  }
  buildTypes {
    isMinifyEnabled = true
  }
}

dependencies {
  implementation('my.company:fancy.library:1.1.1') {
    isForce = true
  }
}

I am definitely biased here, but this is not how an idiomatic Kotlin API looks like.

What we should have gotten

android {
  compileSdkVersion = 29
  buildToolsVersion = "29.0.2"
  defaultConfig {
    minSdkVersion = 21
    targetSdkVersion = 29
  }

  buildTypes {
    minifyEnabled = true
   }
}

dependencies {
  implementation('my.company:fancy.library:1.1.1') {
    force = true
  }
}

Property access syntax and discoverable variable names should have been the norm since day one for it to actually be a good Kotlin DSL.

Complexity

The Kotlin DSL is not very well documented outside Gradle's bits and pieces in documentation. Things like this were incredibly problematic to implement in the Kotlin DSL, at least for me and I found it to be incredibly frustrating.

Conclusion

Again, these are my pain points with the Kotlin DSL. I still use it for some of my projects but I am not going to use it in new projects until Gradle addresses these pains.

Posted on by:

msfjarvis profile

Harsh Shandilya

@msfjarvis

Full time Android developer in Kotlin and Java, experienced with Python and a work-in-progress Rustacean

Discussion

pic
Editor guide
 

Hello Harsh,

I can relate to your pain points.

But I want to point out that you are making a confusion.

Gradle != Android Gradle Plugin

It's a bit the same confusion I wrote about here

Gradle is a bit like SchrΓΆdinger's cat.

Gradle is great
"Gradle" sucks
and both things are true at the same time.

What's the difference?

  • Gradle is a very nice Java API that you can use to build anything. Thinks Makefiles on steroids.
  • "Gradle" in the context of Android developers means Gradle + Android Studio + the horribly complex Android Gradle Plugin + lots of Android build tools that are very often inefficient and buggy.

So when you write:

Gradle doesn't seem to have invested any actual time in converting the original Groovy APIs into Kotlin-friendly versions before they peddled the Kotlin DSL to us.

Actually what you meant is that the Android Framework team doesn't seem to have invested any actual time...

And I can guarantee you it's not an impression.

The Android Team has done nothing at all apart from waiting Gradle and JetBrains to do all the work.

Well they have pretended they did something in a canary release

Android Studio 4.0 and AGP 4.0.0-alpha01 says it has Support for Kotlin DSL script files
The Android Gradle plugin now supports Kotlin DSL build script files (*.kts). When used with Android Studio, certain IDE features, such as the Project Structure dialog and build script quick fixes, now also support reading and writing to Kotlin build script files.

But don't believe it, it's a lie.

1) The Android Gradle plugin does not publish the plugin artifacts to google() repository, necessary for the plugins block to work out of the box issuetracker.google.com/issues/645...
2) The documentation does not include Kotlin snippets unlike most other Gradle plugins github.com/gradle/gradle/issues/6790
3) Adding a module within Android Studio breaks my build. I just tested with 4.0 RC, it still breaks my build by adding settings.gradle files and so on. It would be nice if they stopped breaking the build.

1) is the reason why you find this so frustrated with this commit. It has nothing to do with Gradle+Kotlin per se and everything to do with the Android Framework team having not done their homework.
github.com/msfjarvis/viscerion/com...

3) is such an obvious bug that I'm pretty sure that no-one in the Android team is using Gradle+Kotlin.

Which is why you have those pain points.

TL-DR: Kotlin is the future of Gradle, and also the present of Gradle if you are not doing on Android. But since the Android team has done nothing at all, using it on Android now has rough edges.

 

I agree that my perspective is very skewed because I mostly use Gradle for Android and the AGP/Android toolkit team has not been very proactive. But many of these problems still carry over to non-Android JVM projects I've worked on. The build times are still noticeably slower than Groovy and the code complexity arising from every plugin author not being able to afford being proactive in migrating their codebases. I really, really enjoy working with Kotlin and I would love to be able to write everything in Kotlin but as Howard Stark would say ;)

I am limited by the technology of my time

 

But many of these problems still carry over to non-Android JVM projects I've worked on.

Yes but fixes are coming.
A pain point for me in IntelliJ IDEA is that auto-completion in build.gradle.kts, while great, is also quite slow.
Well, once Kotlin 1.3.60 is released, it is supposed to be 3 times faster.

The build times are still noticeably slower than Groovy

This is also a problem that can be solved... but only if tackled properly. Talking about performance in general is nonsense.

What you should do a Gradle Build Scan and check there is nothing wrong with your build configuration and see what metrics do you have.

The code complexity arising from every plugin author not being able to afford being proactive in migrating their codebases.

Well, once Kotlin 1.3.60 is released, it is supposed to be 3 times faster.

That's great to hear.

What you should do a Gradle Build Scan and check there is nothing wrong with your build configuration and see what metrics do you have.

I have. My configuration had no bottlenecks, Kotlin just took longer to compile than Groovy, and the build scan results for the tasks after the initial compilation of configuration files were nearly identical.

I've taken most standard measures to maximise system performance, I disabled Spectre and Meltdown mitigations on my AMD machines, I've disabled all daemons and services I don't require.

I've tried with and without Gradle build cache and the results have not changed, once configured with the Kotlin DSL, there is a noticeable if not significant degradation in build times.

Not using buildSrc on this particular project. Used it extensively on the Android project where I got 5 to 10 seconds of slowdowns. I don't modify it during most iterative development, only for dependency updates and version bumps where I don't use or build from an IDE.

Ah ah, that part looks very familiar.

In this project you are using my old plugin de.fayard.buildSrcVersions

I noticed exactly the same problem as you: modifying Versioons.kt is not great because it basically forces a clean build every time.

Instead I am now working on de.fayard.refreshVersions that does the same thing, but extract the versions not in code (inside the buildSrc) but in a proper format (that can be read and written by tools) so that we don't pay the penalty price on each update.

See github.com/jmfayard/buildSrcVersio...

Subscribed to the issue :)