'. '

Gradle

From APIDesign

Revision as of 18:30, 13 March 2015 by JaroslavTulach (Talk | contribs)
Jump to: navigation, search

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!

Contents

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 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 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.

As such, if you want a computer program to understand some language, it is important to make the language declarative - e.g. to make it at most as complex as wikipedia:Primitive_recursive_function.

Ant, Maven, Gradle and Tooling

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 could only tech 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 becomes easy - just open then 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 is fragile with respect to 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 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) source code, just declaratively adjust it to your particular use-case. The fact that has to use different language (well XML) to express a use of a pattern is in fact perfect - one can stay more clueless.

Of course, something there is no existing pattern (e.g. Maven plugin) to use. What one has to do? 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!

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 can run it and when it computes the classpath, you can 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). But the core aspects of the project should be understandable without running 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 is tons of services around the globe 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 security is weak and hackers (real ones, not coders) will love it!

Personal tools
buy