4 ms·
I found these to be huge stumbling blocks: - Scoping is mysterious: things that you expect to be in scope AREN'T, and lots of things that you can't see ARE in
by zestyping 6y ago
I found these to be huge stumbling blocks:
- 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.
- p2detar 6y ago> 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. Gradle has build cache since version 3.5 [0]. You probably mean the configuration phase for which caching was introduced in version 6.6. [1] Gradle has been consistently improving the last couple of years. I’m quite happy with its speed since the v6.5 upgrade. 0 - https://docs.gradle.org/current/userguide/build_cache.html https://docs.gradle.org/current/userguide/build_cache.html 1 - https://docs.gradle.org/6.6/release-notes.html https://docs.gradle.org/6.6/release-notes.html
- oblio 6y agoIts architecture is so broken that they had to introduce 3 concepts to speed Gradle up: - daemon - build cache - config cache for a build tool! And it only took them more a full decade to implement them (the config cache is still experimental). And even all those things only take it from "molasses slow" to "bearable".
- pjmlp 6y agoAnd then they sell the image that Gradle is faster than Maven, omitting what went into making it look like that.
- jicea 6y ago> 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, Something that is not clear from the Gradle documentation is that every task must have its input and output defined (inputFile, inputDirectory, outputFile, outputDitectory property). It is absolutely essential so Gradle can infer which task has to be rerun when, for instance, a build is run. This is usually done for the ‘basic’ task (like build, test etc..) but you have to specify it when you have custom task. This can really make a difference in speed. Another trick is to use the console option (gradle build —console plain) so you will see each task that have been run and their status (if they have be runned, or if they have been skipped due to dependencies)
- iainmerrick 6y agoI’ve tried to improve build times on a large Android project, and failed because basically every dependency gets this wrong and it’s impossible to fix them all. This includes things like Google frameworks that you might expect to be well-written. It’s not well-documented, as you say, and beyond that the tool doesn’t do anything to enforce or encourage correct behavior, or offer you any way to fix incorrect behavior in code you depend on.
- larusso 6y agoAs others mentioned gradle has a build cache. It works different to make as it doesn't take the mime timestamp of the input/output but rather creates hashes. In the early versions these caches were project local only. Later the cache was system wide. Now you can setup a gradle cache-server so the whole team can use the same cache. But this all comes of course with some restrictions. Gradle needs full control over the inputs/outputs. If another tool makes a change to an output gradle will mark this as dirty and will rebuild it from scratch. Same when you update java, gradle or plugins since gradle can't be certain that a an update of the mentioned parts would result in a different output. On paper this all makes sense. But if you start to write custom tasks which depend on each other or work on lists of input files this becomes increasingly difficult. Luckily writing tests for custom tasks is easy if one finds the documentation and muse to set this up.
- wasyl 6y ago> Scoping is mysterious It definitely is confusing, but while the rules to scoping are pretty extensive, they're also well defined. The trick is to know how Gradle "travels" through objects and looks for the property in class properties, extensions, extras, etc. I wrote about it [1] if you're interested. > Gradle script is interacting with things you can't see Not necessarily -- yes, the receiver for top-level calls (Project instance) is implicit, but you can access it via `project` property. You could prefix each top-level call in your Gradle script with `project.`, making all calls explicit. Btw `sourceSets { }` calls the lambda on a `SourceSetContainer` instance, accessible via `Project#sourceSets` property [2], so you can get an instance of it. I suppose there might some objects that are configurable but not accessible, but nothing comes to my mind right away, actually. > 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. You might've had a bad experience with a misconfigured plugin/build or a bug. Gradle does track dependencies, and while it doesn't do that perfectly always, it avoids a lot of unnecessary work, on many layers (incremental compilation, task avoidance, task caching). As a general rule, when running the same task(s) twice, the second invocation shouldn't execute any taks. > This is because the entire dependency graph is constructed dynamically on every run It's true that configuration/task graph creation is still happening on every invocation (this will change with Configuration Cache [3]). But it's definitely not accurate that this prevents Gradle from knowing which steps have already been done. Again, I fully believe it didn't work for you, but it doesn't mean Gradle doesn't do that. I'm not trying to say Gradle doesn't have flaws. In fact, I think your comment proves the points from the article. Unless one invests in learning how Gradle works, it's impossible to spot e.g. why the build isn't doing any task avoidance, or understand scoping. It's rather unfortunate, because after that initial investment Gradle is a pretty great tool to work with. [1] https://medium.com/tooploox/where-do-gradle-properties-come-from-bf77e43ee572 https://medium.com/tooploox/where-do-gradle-properties-come-... [2] https://docs.gradle.org/current/dsl/org.gradle.api.Project.html#org.gradle.api.Project:sourceSets https://docs.gradle.org/current/dsl/org.gradle.api.Project.h... [3] https://docs.gradle.org/current/userguide/configuration_cache.html https://docs.gradle.org/current/userguide/configuration_cach...
- oblio 6y agoThat initial investment is non-trivial, though. It's at least tens of hours of study in my experience. And they keep adding concepts and deprecating old ones. And keep in mind this is just for the build tool, someone using Gradle probably already has to juggle a million other details, most likely much more important than Gradle (business concerns, main tech stack concerns, etc.). Gradle is practically consultingware.
- mumblemumble 6y agoI am beginning to think that a lot of these problems stem from Gradle's frameworkyness. You don't call it, it calls you. Whatever it's doing in between when it calls into the bits and pieces of code that you wrote is a mystery. That, in turn, makes it almost impossible to intuit how things in a Gradle script relate to each other. The relationships aren't lexical, and you can't figure out how things work by tracing through the code. Instead, its inner workings feel like spooky action at a distance. If Gradle were more of a library, and a Gradle build script were just a Groovy or Kotlin script that calls into that library, everything might be easier to understand.
- i386 6y ago> Scoping is mysterious Exactly how I’ve felt about Ruby or Rails for the last 12 years. There’s always something magic in scope you can’t see. And duck typing all the things means you just have to trace through the code to actually find out what that <thing> parameter really is and what the function is expecting.