- Scoping is mysterious: things that you expect to be in scope AREN'T, and lots of things that you can't see ARE in scope. This makes it impossible for a beginner to look up the source code (or even, often, the documentation) that corresponds to a given thing in a Gradle file: you might realize that "ext" exists, but there's no way to tell what scope it comes from. That defeats most of the usual approaches that programmers have learned for exploring a new system. To use the UX lingo, Gradle is undiscoverable.
- Similarly, your Gradle script is interacting with things you can't see. When you write "sourceSets { ... }" you're actually calling a method on an object. What object? You can't see it, or even a reference to it, in your Gradle file.
- I came to Gradle with the definition in my head that a build tool is a thing that tracks dependencies so that it only has to rebuild things whose inputs have changed. Gradle doesn't do that at all. Many hours of searching for how Gradle detects changes were fruitless, because it doesn't even try, really. Gradle basically always runs everything, which is why it's so goddamn slow. This is because the entire dependency graph is constructed dynamically on every run, and that prevents the system from effectively retaining from run to run which steps have already been done.