1. 11
  1. 4

    Gradle is one of those things where you have to work with, you take 2 hours to read some documentation, come back to your file and still have no clue what to do with it.

    There’s so much complexity in it, even for basic projects that I just want to switch to an alternative each time I have to work with it…

    1. 1

      Or, as the author did, you get someone else to write the Gradle tasks and config then hope you never need to change it. :-)

      The part where the author talks about the “magic” parts of Gradle and multiple ways to do things really hit home. I’ve spent too many hours googling for examples or answers and only finding seemingly contradictory approaches or advice. On the surface it’s not always easy to spot equivalence when you’re mixing Groovy imperative approaches and the DSL declarative approaches.

    2. 3

      I’m kind of disappointed, since I was expecting something totally different based on the title.

      Having done some minor work on Android applications throughout my high school and university days, I can name a much more significant problem with gradle than Groovy’s syntax: it’s slow! This is mentioned only in passing in this article, but Gradle is painfully slow, and even the smallest, non-android Java projects take a significant amount of time to build, every time. It’s awful if you’re trying to iterate or experiment! I’ve heard this complaint from others, too.

      I really don’t buy into the provided criticisms of Groovy’s syntax. To me, the project definitions are quite readable, and I don’t see many reasons to think about how my project description is computed (and thus how and when the lambdas are invoked). It matters in the case of side effects like printing messages, but then, where did you expect a message to be printed? If you think of a task lambda as “where you describe a task” instead of “the task”, then it’s not all that surprising that I/O happens at configure time.

      And then there are complaints about objects that are “just there”, like tasks and ext. If Gradle is a domain specific language, then these are just its “standard library”. print is “just there” in Python, Math modules are auto-imported in many languages, Make has the “phony” special case. Why should tasks be treated differently? Not being familiar with a language’s standard library is not a good reason to be complaining about the language.

      The variable scoping mechanism is also not that unusual. In, say, Ruby, you can also access local variables from a lambda / block, but not from a function definition. Indeed, the former creates a closure (which, hey, is exactly what the Groovy guys call it!), and that maintains access to the variables that were around when it was declared, while the latter creates a function, which does not have access to the surrounding variables. Having to use a class definitely is a limitation of Groovy, but then, having static fields in that class makes sense, since static variables is precisely how you make “globals” in Java. And if you want a variable accessible from all functions in your file, is that not a global?

      I do agree with the “one way to do things” sentiment, though. Groovy seems to provide a lot of flexibility in expressing even the most minute things, which can be paralyzing for beginners and frustrating for people working in teams. Unfortunately, most languages flexible enough to be bent into a build system will probably be flexible enough to allow many different approaches to solving problems.

      1. 2

        Slow builds suck! There are a few things you can/should do to fully unlock Gradle’s potential:

        Gradle has two phases: configuration and execution. The configuration phase has to run always, so make sure you you don’t have any expensive calls that get run there. This happens often when ppl write imperative stuff into e.g. their task configuretions. Make sure you don’t do that, instead ideally use plugins via buildSrc to contain the imperative logic. Also the latest versions ship with a cache for the configuration phase.

        Make sure build caches, parallel builds in Gradle, and incremental options for your compilers are enabled.

        If you are writing your own tasks, make sure their inputs and outputs are well defined. Gradle can then cache them. You can run your builds with the –info flag to see the reasons for why Gradle is considering a task out-of-date. Maybe some of your tasks are non-deterministic? That can easily happen but once you know the reason it’s also often easily fixed.

        Getting the caching working and minimizing work done in the configuration phase are the main ingredients to get faster builds for iterating.

        For larger builds, you might want to give the Gradle daemons larger heaps (I think 256m is the default setting?) so they don’t get thrashed by GC.

        Best of luck :)