These days it is common to praise Gradle and dishonest Maven. It is hard to find articles like Maven's Inflexibility Is Its Best Feature that would try to put some balance into the build tool flamewar raging around.
It is true that Maven is far from perfect, and possibly Gradle learned from Maven mistakes in many areas, but there is one thing where Gradle regressed totally - and which I consider far bigger problem than any shortcomings of Maven: Gradle brought halting problem into your build job!
Why Should I Care about halting problem?
If you don't know what a halting problem is, you may belong into the camp of people who believe one can write program to solve any (digitalizable) problem. Well, you cannot - there are (digitalized) problems that computer's cannot solve - halting problem is core one with huge implications: As a result of halting problem existence it is impossible to write a program that would completely understand behavior of all other programs.
That of course won't stop people from trying to write such program (as illustrated in the essay about finite automaton), but the only way to really analyse what a program does is to restrict language in which it is written!
Declarative vs. Imperative
Restricted language is in my opinion the biggest difference between imperative and declarative specification of actions (and by declarative I don't mean functional as such languages suffer from halting problem presence as well). A declarative language/specification should not allow people to express everything that is possible in (Turing complete) imperative language.
Btw. the important element that needs to be avoided is while construct - e.g. repeating some code block indefinitely - repeating something via for cycle - e.g. given number of times (with respect to particular input) is OK. Languages that restrict itself to just fixed number of for repetitions fall into the wikipedia:Primitive_recursive_function definition and are not subject to halting problem - all of them halt.
Ant is in general considered too lowlevel, too imperative. It doesn't have direct way to express while, but as it has a way to invoke a target recursively, it is also subject to halting problem. As a result it was impossible for a tool like NetBeans to analyse a generic Ant script and extract for example project's classpath and/or test classpath without really starting the build. In spite of that NetBeans IDE 4.0 used Ant as its default build harness and supported two way editing - one could change scripts and configutation files from a command line and the IDE was able to pick the changes up and adjust its settings automatically. However, this worked only for small subset of Ant projects with well defined structure the NetBeans IDE could understand to.
Some (especially Ant fans) consider Maven too magical. Doing too many things in a blackbox. Well, that is what one gets when doing things in declarative way - you don't specify commands to compile, copy, delete like in Ant - you express intentions. What actions your intentions result too is a blackmagic. Maven's language to express intention is a DSL embedded into XML. Yeah, the XML hype is over - but clearly there is no way to express while statement and as such the Maven configuration is not subject to halting problem and it can be analyzed by the tools. When NetBeans IDE decided to support Maven out of the box, we "only" needed to teach it to understand the pom file dependency section and few configuration options of most commonly used plugins (like maven-compiler-plugin - to read the source and target levels, encoding, etc.). Understanding completely unknown Maven projects became easy - just open them in the IDE and all the settings are immediately known. Change the pom file on disk, and the changes are immediately reflected. Don't believe it? Get latest version of NetBeans and give it a try - Maven support in NetBeans is really smooth.
Now you can probably see what is the biggest Gradle flaw. Yes, by choosing Groovy (which support while and as such is subject to the halting problem) as its configuration(!) language the system immediately lost all its tooling potential. We are back in the Ant-age! You need to run the build to understand what it will actually do. From a tooling story perspective: Gradle is total disaster.
Hacking vs. Defining Patterns
We have all heard about design patterns and how useful they are. Maven in fact excels in defining such patterns: Do you want to compile using JavaC? Well, there is the maven-compiler-plugin - the plugin is in fact pattern - it is a solution to recurring problem. But rather than trying to recognize the pattern from a (Java or Groovy) source code, you directly speak the pattern's language - you name it in the pom file and declaratively adjust it to suite your particular use-case. The fact that one has to use different language (well over hyped XML) to express a use of a pattern is in fact perfect - one can stays clueless - and is not tempted to hack.
Of course, some things cannot be achieved by using existing patterns (e.g. Maven plugins). What one has to do then? Define new pattern! E.g. create new Maven plugin - e.g. solution to recurrent problem - code it in Java, but hide the code and expose only its declarative configuration. How structured! How architectural! How much better than classical hacking! Of course one can run into the halting problem issues in Java, but it is far easier to verify correctness of implementation of few patterns than check correctness of every build script.
Because we all know what you do when ready made solution cannot be found in Ant and alas, also in Gradle: you hack. You use all the power of complete programming language around to write a solution. Thinking about patterns comes later - if ever! As a result majority of Gradle build scripts will have some non-standard customization.
Gradle teaches you to hack. Maven teaches you to design!
Cloud and Security Issues
Maybe you are a Gradle fan and nothing mentioned so far convinced you. At the end, what is wrong on having build system subject of unidentified complexity. You run it and when it computes the classpath, you write it down into static file which can then be consumed by various IDEs. Yes, this is possible, but it is upside down! Moreover unsecure.
Generic information like classpath, etc. should be extractable without running unknown code. So the core of the build configuration should in fact be those files consumed by IDEs. If there is anything else needed for the actual build, it could be written in Ant or Groovy (in spite I would rather advocate using AnnotationProcessors as much as possible). But the core aspects of the project should be understandable without running any code. Because you don't want your IDE to hack your computer after you checkout a GitHub project and browse to its sources or open one of its files in editor!
Another issue is CPU time: there are tons of services around the globe (Ohloh comes to my mind) that provide you indexing services over source code. Usually they just analyze commits, do static analysis of the code, etc. But there is nothing stopping them to understand structure of Maven projects and know cross-dependencies and resolve symbols to proper fully qualified names. However nobody is going to offer such service for generic Gradle projects! Because in order to analyze them you need to run foreign computation and that can eat enormous amount of CPU and do potentially anything and nobody is willing to offer free computation time so easily to everyone!
Gradle is designed to be insecure and hackers (real ones, not coders) have to love that!
My friends keep talking about the greatness of Gradle and when I bring the problem of Turing completeness - e.g. halting problem - they just nod their heads, admit tooling is a problem, but continue to use Gradle. Fine with me. By writing this essay I don't expect people to stop using Gradle - I just want them to stop claiming Gradle is superior to Maven.
This essay attracted attention of Gradle community (for example Schalk Cronjé's post) and I received some valuable feedback. I don't think it can change anything on the points raised in this text as facts are facts, but it is useful to have wider context and understand motivation.
The road to hell is paved by best intentions - and I am sure Gradle guys know it. If you listen to whole (or just jump to 48th minute) presentation by Hans Dockter, the father of Gradle, you will notice. Let me quote: "We just don't know if someone calls System.currentTimeMillis() here... This is I would say the biggest design flaw!"