Hacker News new | past | comments | ask | show | jobs | submit login
Why I Moved Back from Gradle to Maven (philipphauer.de)
174 points by ognyankulev on April 3, 2018 | hide | past | favorite | 168 comments



Flexibility is not something I want in a build system. I want predictability and simplicity. "Flexibility" just means that the dumbest guy on the project will find sufficient rope to hang the whole team sooner or later.

That being said, "flexibility" is not special to Gradle. As long as there have been build systems there have been people who are too lazy to learn them and get "bright ideas". For instance I have no idea how many shellscript-infested build setups I've seen for C programs that could easily have been built using entirely standard Makefiles. If the author had bothered learning to use Makefiles.


> Flexibility is not something I want in a build system. [...] "Flexibility" just means that the dumbest guy on the project will find sufficient rope to hang the whole team sooner or later.

We're on opposite sides here. I can control my team wrt rope and what not. But it's very hard to wrangle a build system to perform some advanced task you need without flexibility. I'd way rather have problems with the build system users than the build system authors. One is more easily fixable.


At least in Maven, the answer here is simple: write your own plugin.

You can do whatever you want, but you're still operating within the confines of the build system so you've not lost the ability to see what's going on.

It's not all that common that I see an "advanced task" that actually belongs in the build, though -- more often I see people who have decided to fight against their tooling rather than working with it.


I've experienced this myself in a number of different environments. But I'm still not satisfied with the results with the more flexible tooling, usually. I think it's because they commonly lack scaffolding that I want a majority of the time.

The older I get, the more I realize that the lisp DSL approach is probably best: provide a simple, declarative walled garden. If I want to change something for my project using the full language, let me, and may the PR reviewers determine my fate. Ruby also seems to adhere to this philosophy, although I don't have a lot of experience with it.


> I'm still not satisfied with ... more flexible tooling ... they commonly lack scaffolding that I want a majority of the time.

I think this dichotomy, flexibility vs maintainability, reflects build complexity.

Not only do I think the same-language-DSL (a la LISP, as you pointed out), is the 'least bad' choice, I think if we raise our gaze a little the answer here is painfully obvious: how do we handle those issues everywhere else?

In other cases if you need to move files, call some sys commands, structure some data, and express some logic? What if you have to call a webservice with some throttling logic, where is your "build language"? Plop something in a DB? Not to mention that complex builds often have specialized command line apps called by their specialized build langauge.... why?

Complex logic we use programming languages for. Why sacrifice power, components, libraries, compiler-time-checking, and all the rest to use a lesser tool? Full language power, it's The Right Thing.


> may the PR reviewers determine my fate

Confused here. I can't really stop progress waiting on build system features. Extensibility is required like a programming language. Otherwise, you must stop using the build system or build wrappers around it or outside of it making your build even more bespoke than if you used a more flexible system.


That's my issue: missing build system capabilities leaves me writing console apps to make builds sane.

If I'm writing code anyways in MyLanguage to compensate for MyBuildScript, why aren't my build scripts written in MyLanguage?


I agree. With an inflexible build system we still end up with the nasty shell script but it's worse because it wraps the build system.


Maybe combine a generic non-language specific build system (some variant of Make without the C obsession?) as the outer wrapper around a very language-oriented and inflexible/opinionated build system?


> some variant of Make without the C obsession

Make doesn't have a C obsession (although the docs do), make works anywhere you have a dependency graph that can be expressed as a file timestamp. Here's an example compiling a c# project: http://flukus.github.io/rediscovering-make.html . It's much simpler than any .net build tool (and I've tried them all).


Either you have a very strange concept of simplicity or you never tried Fake.


That's one I haven't looked at much, but can you show me a fake script that does the equivalent of my example? That means a fully incremental build, generating version files, etc. Even things like the version file tend to turn out more complicated in most build systems because they come with a half assed reimplimentation of unix tools

From a quick look t looks like it's task based instead of output based as well, so an incremental build doesn't look simple. Correct me me if I'm wrong, but it looks like it's trying to be a better nant, not a better make.


You're assuming that you're around when the team is building out said system. What if you have the misfortune of inheriting a system where there was plenty of rope to go around?


Still better than having to abandon the build system altogether because it can't do what I want (or work around it which is often worse than leveraging flexible environments in the first place).


Perhaps you can control a team, but how many people do you think you can "control"? Could you control every developer in a division? A company? And how do you onboard new people if any past experience with build systems is worthless because they have to learn how you do your particular build?

And if you find yourself consistently not being able to build a piece of software with a relatively simple build process, perhaps you are trying to do too many weird things?


> "Flexibility" just means that the dumbest guy on the project will find sufficient rope to hang the whole team sooner or later.

In my experience, it's not dumb but clever which you should worry about — those are the ones who'll spend two weeks making something completely unmaintainable after reading someone's post about how some esoteric mathematically pure style delivered a 7% performance increase on an edge case.


"Clever" is just a polite way of saying "dumb" :-)


It's a different concept — closer to the difference between intelligence and wisdom. Someone who is cleverer than they are wise can go a long way before recognizing that the approach they're taking isn't cost-effective, especially if it gives them some point to feel proud about doing something which (correctly or not) they feel most other people couldn't.


Lack of flexibility means that it will only work for xx% of projects (supply an arbitrary value for xx but other than 100, by definition).

Then what it means, is that 100-xx percent of projects are going to be screwed up.

Not everybody lives in a nice world when the project is a single web application with 4 microservices and a shared library maintanied by a team of 5.


Out of those xx% of projects, how many really need the flexibility? Based on the last 30 years or so of being a developer, I would be tempted to believe that it would be in the low single digits.

It is sometimes worth it to spend a little extra time as you set up the build process, and as you make decisions on how to organise things so they can conform to a build process other people will understand. Quite often "clever" builds on long-lived projects, or projects with many developers, have a higher cost in terms of effort than what you save on "clever" shortcuts.


Well, if you will allow such a guy to operate alone without any code review, then I'm sure you have much more serious problems in the code, than a build system.


Most complex build setups I've seen in the wild the last 5 years were made by teams that have mandatory code reviews of all code.

This isn't so much about review or not as it is about not establishing a culture where you always take the easy way out. It is tempting to think that "this will be solved through the magic of code reviews", but if you are in charge of several teams and you have to face the reality of projects living on for years with people joining and leaving the team. It is important to have empathy with developers and your future self.

Much build complexity and annoyance is due to people taking the easy way out, for instance, by scripting things that should either be adapted to make use of an existing build process, or develop a proper plugin that is documented and helps newcomers to the project understand what is going on.

If you make it easy to make ad-hoc solutions, people will build ad-hoc solutions.


Yo, new Gradle developer experience lead here. I fully empathize that it's much too difficult to wrap one's head around Gradle, so I want to share some things you might find interesting:

* The Gradle Kotlin DSL, which is nearing production-readiness, substantially improves the assistance/docs one gets through the IDE.

* However, the Kotlin DSL does not help with the large API surface and understanding of Gradle concepts, so I have been working on improved docs and best practices for the past few months.

* However, most folks don't or won't read docs, so additional tools will help users opt-in to strictness and quality checks that enforce best practices through the tool.

Even with all that, one can think of build tools like languages: one tool will never be able to suit all needs or projects. However, I intend the broaden the audience for Gradle by making it more accessible to a wider audience.

I'd love your help. My Twitter DMs are open @eriwen. DM me the 1 specific thing you would change about Gradle if you could.

[EDIT]: Fixed the formatting of the bullet points.


The key point that Gradle needs to make clearer is to delineate between task creation and task execution and which code is running where. It is very confusing for people to know whether their code is going to execute at gradle file load or at task execution. People get confused that they can't just use the result of one task when setting the opts for another.

Edit: Also, I personally do the opposite route wrt the paradigm of the wrapper and the daemon. I don't commit a wrapper script and have people use a downloaded Gradle themselves. I also run --no-daemon on every manual execution for smaller projects. But I may not be normal here.


Definitely agree with this. The Gradle lifecycle and the difference between Task Execution and Build Configuration is not intuitive at all. Neither is the fact that when you just stick a `<<` or `doLast()` in there without understanding why, it works with some tasks and not with others (killing << is a step in the right direction but making the build lifecycle more understandable would be hugely helpful).


I used Gradle for a year or so before i grokked this distinction. Once i did, things became very simple indeed.


Personally, I think Gradle (and a whole lot of other software) needs to stop the whole convention-over-configuration idea. It makes things way too difficult to debug and learn from, all to save some one-time typing. Making everything implicit for the sake of simplicity is really just the opposite.


> needs to stop the whole convention-over-configuration idea

Yup, and while we're at it, realize that the declarative approach doesn't work after the first basic uses and even though your hello world build file is simple, most people need customization. Scripting the build system should be its main feature and everything else as just shortcuts (to be fair, Gradle kinda does this w/ tasks, but doesn't make it simple to just drop into code).


This may be naive but doesn't GNU Make tick all these boxes in addition to being ubiquitous?


I like make, but no. Try out gradle; it really does support complex project structures in a much more natural way than make does or even can.

For example, have you ever wanted to break a large project up into subcomponents with build-time enforced dependency relationships? This is trivial with gradle but very hard/custom to do using make. gradle is aware at a domain modeling level about components of a project, their dependencies, and the implementation and interface artifacts they generate. I think this is really cool.

Their native support is still evolving, so it probably can't drop-in replace more complex native builds, but a few years ago I had it building a shared c++ codebase for macOS, android-linux, and iOS. I could test the core on macOS locally as its own project. I had google-test built locally and specified as a dependency (a sibling project) rather than prebuilt and plopped in a vendor directory. And the code was mostly free of ifdef android or macos etc. because I could not only enforce separation at a project level, but also easily provide a place for platform specific glue to live (in their own sibling projects). It was really cool and would have been a lot more work without gradle.


Not ubiquitous and missing shortcuts. How do you compile 5 JVM projects in different JVM languages, sharing different configured sets of potentially hundreds of libraries across the classpath and make sure there are no versioning conflicts? Shortcuts are required, they just don't need to hide everything.


I guess I'd compile them like anything else: using Make to invoke the compiler.

Checking versions can be accomplished by using awk or another tool to compare output from $compiler --version.

What am I missing?


Your makefile / build script would grow so complex so as to start reimplementing maven or gradle.


What if two things share a dependency?


Do you mean a conflicting dependency in one of my 5 projects? If so, it's on me to pay that technical debt and fix my own crap.

If the dependency doesn't conflict, then my package manager takes care of it.


In the JVM world it's not uncommon to have different sets of versions of the same libraries for different but dependent projects. And it's not a problem, because classloading is hierarchical and so different versions can live side by side even inside one JVM.

And a lot of Java/Groovy/Scala/Kotlin libs are on Maven Central, but not packaged for let's say CentOS/Ubuntu/Debian/etc. So the package manager for JVM is Ivy (ivy2), or full Maven (which is basically ivy + a task runner).


GNU Make has a huge amount of convention over configuration. It has hundreds of built-in pattern rules!


If you want ideas, you should check out Ratpack (a web framework for Groovy or Java) and the way the Ratpack.groovy DSL looks.

* Convention over configuration: implicit defaults for everything so the hello world example is very simple. If you try to create a new Java project in Gradle, not by copying and pasting or having the IDE autogenerate something for you, you're going to have a bad time. * Whenever you do want to add something, there is a clear place within the structure of the root ratpack{} closure to add it. The port goes under serverConfig, routes go under handlers, etc. You don't set the port under the routing handlers, that would make no sense. Very different than build.gradle which feels like a flat list of unrelated tasks. * Support for both anonymous code and for code which has been factored out. Of course Gradle supports this (factoring out buildscript dependencies instead of a flat build.gradle) but the experience makes you feel like you're playing around with Frankenstein's monster so hardly anybody ever does so. * Documentation provides examples through tests, which clearly show both the code and the expected outcome, and which Ratpack prioritized being able to express in a concise manner precisely so that it could be used for documentation purposes.

Could Ratpack have gotten rid of the root ratpack{} closure, the serverConfig and handlers and registry closures? Technically yes, they're not needed to namespace their children. But it would be so much less understandable.


Using maven at work and Kotlin-DSL for my personal projects. One of the main pain points for using Kotlin DSL is the speed. It's order of magnitude slower than maven when used with IntelliJ IDE. Sometimes updating the `build.gradle.kts` file and reflecting the updates on IDE can take up to 5 mins. Apart from that really love the improvements made by Kotlin DSL. Finally, I can write the build script without going through the docs/stack overflow all the time.


Fix the documentation!

Focus on Android Studio because that's the only place people really use Gradle because they are forced to do so.

You need to create a LOT of Android Studio sample projects, and they need to be kept up to date for the various versions of Android Studio. If you did nothing but create "Hello World" in a zillion various flavors (Java, Kotlin, Scala, NDK, NDK with static library on different architectures, etc.) for people, that would be huge.

My specific beef is with NDK projects. Pulling in static libraries and compiling them with the NDK is a mix of magical keywords that sometimes materialize from some kind stranger via chat--generally because Gradle has to shove those keywords to something like CMake--which ALSO has an enormous learning curve.


Please don't say that nobody uses Gradle outside of Android devs. We're a shop that definitely does zero Android development and we still use Gradle, the fact that people assume Gradle <-> Anroid Dev is already a huge pain point for us when we start looking for third party educational resources.


At our shop we only care about Gradle, because Google forces ud to.

Otherwise we would keep using only Maven for Java projects.

Slower builds and higher hardware requirements for daemon and build cache are not worth it.


> Focus on Android Studio because that's the only place people really use Gradle because they are forced to do so.

False


It is true for us.

If it wasn't forced upon us for Android dev no one at my employer would even bother to learn what is Gradle.

The opinion is that it is the last spot keeping Groovy alive.


Jenkins also semi-recently decided to go with Groovy for their "pipeline" feature. Ugh.

(They may have good reasons, but anything that prolongs the lifespan of Groovy is a bad thing.)


Thanks for the feedback. Docs/samples oriented around Android could use some love for sure. I think one thing we need to figure out is how Google and Gradle can accomplish these things together.


> I think one thing we need to figure out is how Google and Gradle can accomplish these things together.

We refer to that in the corporate world as "death by committee".

You can solve the problem with a GitHub repository and an intern trawling StackOverflow and IRC logs. Choosing not do that sends a signal.

Waiting for Google to "accomplish it together" (aka sometime before the heat death of the universe) is a good way to get replaced.


While all Android Studio users are forced to use Gradle only handful will ever need anything more than the basic boilerplate generated by Studio.

My Android projects are mostly private stuff but I don't remember any project that would require any kind of custom build. There is whole plethora of tools. My own calculators for various stuff, app to communicate with my family, apps to manage my electronics (bluetooth, wifi, cloud), apps to manage stuff in my Drive. My changes are mostly adding dependencies.


Try to integrate NDK builds or follow up on the continuous suggestions given at any major Android conference about how to speed up builds.

That basic boilerplate is no longer enough and tricks change with each release.


The gradle team doesn't work on android builds. They work closely with Xavier from googles android build tools team on that.


I moved from Maven to Gradle about two years ago and I am not going to look back.

I understand the arguments made in article and I am the Gradle ninja in my project so I may have subjective view on the whole topic.

My points:

- Maven requires a lot of boilerplate for everything. Copy-paste. I need to instruct everybody on what to copy, where to paste, and how to edit and what they should not touch under any circumstances.

- Gradle... It's an environment for programmer! I just write a bunch of code in Kotlin so that all 100 projects have a bit of my custom DSL that suits the needs of our application. The code takes the DSL and does all the job behind the scenes and most developers don't need to understand it. They can, but they don't need to. This is how it is supposed to work -- in a large project people specialize and the application should be created in a way that will allow people to not have to understand everything.

- Maven is strictly declarative. If you can't find a plugin you either dig up Ant or you have to write your own plugin. Not nice.

- In Gradle I can have almost everything declarative but I have the freedom to drop this bit of logic where it is really needed.

- Don't try to make it too complex just because you start using Gradle. Great power comes with great responsibility.

If I wanted to change one thing in Gradle it would be for the Gradle project to focus on debugging. I really find it difficult to figure out why things fail even though I have almost 20 years of experience with various languages and a decade of very intimate experience with Java. Make it easier so that people are not put off.


I'm neither Maven nor Gradle ninja. Just a senior software developer with 15+ years of experience...

> Maven requires a lot of boilerplate for everything. Copy-paste

I think you may be doing it wrong. Maven supports declaring project-wide or module-wide entities and their attributes at every level. Duplication or copy-paste is a sign of not understanding Maven

> Gradle... It's an environment for programmer

To me this is a counter-argument. When I need to understand project configuration I expect structure, not behaviour.

> If you can't find a plugin you either dig up Ant

Been doing Java software engineering for many different projects in various industries on all scales and I only had that problem once or twice.


> > Gradle... It's an environment for programmer

> To me this is a counter-argument. When I need to understand project configuration I expect structure, not behaviour.

Agreed. Every time I see a build system that lets you write arbitrary code, I shy away from it. Builds should be standardized, not a mess of custom code. Maven lets you write plugins for the case when you need to do something truly custom, but in my experience that's vanishingly rare.


I think the difference between arbitrary code in buildfiles and an obscene zoo of plugins running arbitrary code is rather small in terms of actually understanding the build.

My takeaway from using both maven and gradle is that I would really love to have a build system with emphasis on allowing custom arbitrary code, but only within guiderails that force them into a shape that is easily factored into a plugin if you layer decide to do so. Maybe even with a defined reverse path for unboxing existing plugins back into their inline form (for when you absolutely need a fix/unexpected customization, but can't commit to fully maintaining the plugin)


> I think the difference between arbitrary code in buildfiles and an obscene zoo of plugins running arbitrary code is rather small in terms of actually understanding the build.

Completely disagree. Off-the-shelf plugins behave in defined and documented ways, and understanding a build that uses a particular plugin just means reading that plugin's documentation. When you allow arbitrary code in the build file, it means you have to puzzle out what the author was trying to do, for each and every case where you see unusual arbitrary code. You also get into situations where there's more than one way to accomplish many tasks, so you have to learn all of them instead of relying on a standard built-in method.

Sure, any random maven user in your organization can write a plugin to add undocumented behavior, but I rarely see that happen in practice. Even though writing a maven plugin actually is pretty easy, there's an implied barrier both in setting up a plugin project and writing it, as well as publishing it in a way that that a consuming build can use it. So you end up with it being rare to write a custom plugin. There are very few things you can't do with off-the-shelf maven plugins, and arguably I'd rather be restricted and be unable to do some things than have to deal with the mess that arbitrary code creates. I've seen it time and time again with people who try to introduce sbt into my org, and it makes me want to scream.


It took a while for me to fully understand Maven. I tried to look at plugins to understand it, but I struggled. My experience with Gradle was different. After reading the source of a few plugins, I understood that Gradle at its core is just tasks + variables / objects that add syntactic sugar to the DSL. Today, I find Gradle more accessible and flexible than Maven.

Its a bit unfortunate that a lot of Gradle tutorials start with the syntactic sugar.


I understood much of Maven better after writing a Maven plugin. After doing the first I lost my hesitance to write one if needed. I can only recommend that.

Until then I had pretty much a hate relationship with Maven. Mostly tests failed due to improper excluded transitive dependencies. Once writing your own plugin you understand depenendency management and class-loading much better.


It may be you are doing plain simple (can be large, but still simple) projects for which Maven is perfectly fine. Gradle is for when you require some more complicated behaviour in your project.

For example in my current project the applications are packaged into completely custom and proprietary package that is then being used by the completely custom automation to be deployed to the infrastructure.

I have created a DSL which allows people to specify rules concerning how their projects are supposed to be treated when they are being included in one of these large packages. I have also placed some extension points that allow people to attach their automation. The extension points are there so that automation tasks that are specific to projects don't have to all live in a single gigantic automation script (out of my control) but can be nicely separated for each project.

Mind that we are not putting automation in the build script. The build script is there to organize the process not to be the place where you put your commands.

Now, I don't even want to start thinking how I would do this with Maven... probably would dump this work on somebody else...


> For example in my current project the applications are packaged into completely custom and proprietary package that is then being used by the completely custom automation to be deployed to the infrastructure.

If you really need something insanely custom, you can just write a maven plugin (it's actually really easy to do so).


Not as easy as using gradle. I've written a couple maven plugins in my time, and I'm so very glad we have gradle now.


Right. And in my opinion that's a strength. I don't want it to be trivially easy to do something custom. I want the person who thinks they need to do something custom to think long and hard about it, and really pause to consider they might be approaching the build issue in the wrong way before plowing ahead with some custom, (often) unmaintainable code. Having guardrails in your build system that are difficult to jump over is a good thing.


Maven plugins still have lots of structure to obey, but you can treat the plugin as a black box very easily. Other people dont need to understand the innards to compose the plugin with other plugins.

I'd be hard-pressed to see how you can do that with gradle.


Gradle plugins work exactly the same. The only difference is that you define a task of the type a plugin exposes, configure it via its API and define dependencies to other tasks. Not very different from configuring a Maven plugin.


Can you supply an online tutorial of this approach using Gradle? ... I'm not sure what to google to find it myself (I don't use Gradle, but it sounds powerful).


The concept of DSL is quite popular and well known. It can be effectively implemented in almost every language, but some languages are better suited to DSLs than others and allow hiding the underlying language structures (this is so called "syntactic sugar").

Here is a small example I just googled: http://mrhaki.blogspot.com/2013/05/gradle-goodness-extending...

The main idea is to use the language to create another language layer, better suited to the task at hand.


Thanks, no idea grandle has 1st class support for creating DSLs and I overlooked the 1 keyword you had in your reply -- my bad. In general I am familiar with dsl's.

Appreciate the feedback.


> I think you may be doing it wrong. Maven supports declaring project-wide or module-wide entities and their attributes at every level. Duplication or copy-paste is a sign of not understanding Maven

That, and it sounds like the parent doesn’t understand POM inheritance and archetypes.


For me the main difference between Maven and Gradle is the way I read them.

Maven is declarative. Yes, it has some boilerplate, it may not look nice (I'm not a big fan of XML), but the main advantage for me is that I can read it easily and understand what it does. Because it just declares tasks. Similar to any other XML file or JSON or .properties. You just read it.

Reading Gradle, on the other hand, is more like reading a program. You can't just read it, you have to interpret it, you need to put effort in order to understand what this program does.

Yes, Gradle may be more flexible and less boilerplate, but personally I don't want to have another program (in another language) to just build my project.


>Gradle... It's an environment for programmer!

>Maven...you have to write your own plugin. Not nice.

>If I wanted to change one thing in Gradle it would be for the Gradle project to focus on debugging

You've just explained why I have no interest in Gradle. You're writing one off, undocumented, anonymous plugins, in a weird domain specific language, with debugging tools that aren't very good.

Worse, when the Gradle guru decides to leave the company for greener pastures, everyone else is left with a mess trying to figure out WTH that person was doing in all the build files.


Yeah, especially code like that:

artifactory { publish { repository { repoKey = version.endsWith('-SNAPSHOT') ? 'libs-snapshot-local' : 'libs-release-local' } } }

In Gradle, this is immediately understandable to everybody. You can't do this in Maven without plugin support or some very protracted constructs.

Sprinkling those small bits makes the Gradle useful. We are not talking about making a beast of a build system, just provide you with an ability to solve your problems.

You may not want or like to learn another tool and that's fine. But don't think that just because you don't see the reason it means its not useful for other people.


You're now contradicting yourself:

>I really find it difficult to figure out why things fail even though I have almost 20 years of experience

>In Gradle, this is immediately understandable to everybody

You pulled an easy example to defend Gradle for the exact problem you just complained about.

>You may not want or like to learn another tool and that's fine.

It's not about like or want, it's about having the wisdom to recognize a poor solution before investing time in adopting it. OP fell for the hype. Maven works fine for me, thanks.


This sounds like a process problem, not a gradle problem. I don't think there's inherent readability to maven, and I'd love to share my previous employer's pom files with you.


Honestly I can't believe people are arguing for maven over gradle... switched an entire very large org, all our java projects to gradle from various things over the last few years...everyone could not be happier. So much simpler, I only hear happiness from teams. Still run by a maven dumpster fire here and there though for the holdouts


I have been a user of make, Ant, Maven and Gradle. And Grunt, Gulp and now npm + webpack in the JavaScript-world. And of all these Maven is by far the better build tool.

To the creator of these tools: Try to remember that what you are creating is a support tool. A second act to the main development language. It is better if it is not general purpose, it is better if it is not turing complete, it is better if it is less powerful.


I don't spend a whole lot of time in the Java world, just enough to take care of small requests. So, I've only experienced maybe half of those. Could you explain a few killer reasons why Maven is the better build tool?


It is a bit like explaining zen but I will try.

A programming tool has a certain affordance. It talks to the programmer and says "hey - here is how you use me".

Maven says: Hello. I am a just a configuration file. Just put your project's name and the dependencies in here and the defaults will take of the rest. You remember Ant? Please don't turn this into a big mess.

Gradle says: Oi buddy. I am a full-fledged scripting language. Anything Maven can do? I can do the same times 10. Plus my syntax is tight - just look at this &#€#"&/+=+++ << '${.&%&}' ... Not even a semi-colon.

You see the cool kids over there? They all have advanced build scripts with code generation, variable substitution, dsls, database migration, performance daemons. You need this too (unless you are one of those corporate XML-dorks ... yuck XML, it sucks, no one uses XML anymore).

And because we are so cool, we change all the time so you better keep these random files we generate for you under version control: gradle/*, gradlew, gradlew.bat besides your actual build script.


All maven builds are exactly the same (unless they force the tool to do otherwise), and files are always in well known locations.


How that's different in Gradle?


You are actually programming in Groovy, with all the plus and minus it entails.

Regarding the execution speed, IDEs not able to autocomplete, no guarantees about the format that IDEs can easily parse, and it often breaks between releases.

Then to compensate for lack of speed, you need to have a running daemon and an in-memory build cache.


If your build generated sources (such as via antlr or some other lexer/parser that has a maven plugin) at build time, you know that it's likely to be done at the 'process-sources' phase.

If you wrote a custom gradle build script (or indeed, any other custom scripts), then you cannot be sure when that generation of sources is going to happen.

Maven forcing you to design your build around maven's fairly strict set of phases (and build lifecycle) means you confirm, and any tooling can compose as long as they also conform.


I spent a good 18 years in the Java coding stack. I adopted Maven when they just released version 2 and watched one of its evangelists talk at a JavaOne. Obviously now it's insane to think about a programming language that doesn't have a dependency manager (even C/C++ has Conan!).

After a long time fighting between what I liked best between Maven or Gradle I realized that the only thing I really needed was the parts to build the Java code. Things like Docker, Java code generation and a variety of other tasks you often do for releases, I finally figured out what I needed to do:

Make sure everyone on the team can run Bash. From there I could stop worrying about Windows users - Git Bash or Babun or some flavor of Cygwin. And things are even better with Linux Subsystem for Windows.

Now we simply have bash scripts that do all our one-offs that often were nightmares to accomplish in Gradle or Maven. Whether it is JAXB or Docker integration every maven/gradle plugin I ever used was 10 times harder than just bash.

When you start taking out all the other stuff it started to become clear that Gradle was winning out. With gradle I can build my code and get a variable that represents every JAR I need for a deployment into a Dockerfile containing folder. So that's where I personally ended up liking Gradle more - because I stopped depending on Maven and Gradle to do the other kitchen sink tasks.


Honestly, I have the opposite opinion. I really don't like it when there are custom bash build scripts. And you have to figure out how they work and what they do. And how to pass additional parameters etc.

If you use Maven for your project, then I expect that if I run `mvn clean install` then it will build the project.

I think that is the whole point of standard build tools: that you can switch projects easily, run the same command and get the same result, and not waste time learning custom scripts for each project.


This is a common problem for programmers in general, not just at build time. Occasionally you will run into a case where the framework you've chosen just doesn't fit. You can try to hammer your need into the framework in some horrific fashion or your can temporarily circumvent it for this one task. Which path you go depends on a lot of factors.


I think FAKE (https://fake.build/), hits an amazing sweet spot for this: standardized, predictable, with no sacrifice of programming/platform power when dealing with builds.

Project to another, just run "build.fsx" with the desired target -- it will self-download necessary tools and packages -- and you'll get a straightforward standard build. If you want to see the logic, just open it up: build scripts are standard F# scripts

Because you're using first-class scripting you get full language power, full component and package management power, full abstraction power, aided by a set of utility methods and tools. At any point things get hairy you can wrap them into a lib, or a full program, with no domain impedance. It's standard code, as learnable as the rest of the F# proj, no voodoo, no black boxes.

Heck, you can also load your project and use its libraries during the build. I find myself often using FAKE components in my main solutions to take advantage of its interop and publishing...


> Now we simply have bash scripts that do all our one-offs that often were nightmares to accomplish in Gradle or Maven. Whether it is JAXB or Docker integration every maven/gradle plugin I ever used was 10 times harder than just bash.

This is the opposite of my experience. Trying to get consistent behaviour out of bash scripts is a nightmare (every nontrivial bash script has an undocumented dependency on a particular version of some system tool, every time you try to build on a new machine you're rolling the dice). Maven plugins are versioned and (usually) tested, have sane defaults, and will Just Work (provided you're willing to roll with their defaults rather than fighting it).


Funnily, 10 times harder is exactly my experience with most maven plugins. Maven is fine if you stick to compile, test, and jar. Anything beyond that just tends to escalate into madness.


> every time you try to build on a new machine you're rolling the dice

why not on copies of known-good machines? vm boxes with the same definitions would alleviate almost all of that 'roll the dice' aspect, no?


At that point you've frozen a working image of your dependencies along with a bunch of other stuff, but you still don't have a clear picture of what those dependencies are and how to work with them.

Your build works in a vm of RHEL 5 with packages x and y installed, ok, now you need to add a new build step that depends on something that's only available for RHEL 7. So you run the VM generate script (if you can even find it a year or two later) and the build doesn't work. Now you get the same fun debugging experience. Standardising which OS and package installs every developer uses (whether with a VM or just with something like Puppet) means you get to roll the dice less often, but it's still a dice roll whenever you want to change something.

And running all your builds in VMs has a cost in terms of performance but more importantly in terms of comprehensibility. If my build is just Maven I can run it in my IDE, then I can push one button differently and run it in my IDE with a debugger attached. If the build is running slowly and I'm not sure why, I can push one other button and now I'm running it with a profiler. Some of that is just an argument for having your build tooling written in the same language you're using for development (if I was working in e.g. Python, I'd be more likely to have a Python IDE and a Python profiler to hand, so would want to use a Python build tool), but even if you're used to working in Bash and C I'm not sure the VM advocates have good answers to how you debug something running in a VM as yet.


I do something similar but with a Makefile as the top level. Every project I work on has a top level default that will fetch dependencies and build the project.

Lower level recipes are either one liners that invoke a project specific builder (ex: mvn package) or they invoke a separate bash script.

For complicated polyglot projects it works great as each component can use its own native tooling yet the top level is consistent.


> Now we simply have bash scripts

Hm - I don't know about that. The biggest issue I found with Gradle was that it offered unlimited flexibility, and inevitably, somebody would mickey mouse sorcerer's apprentice the thing and stick something into the build script that didn't belong there. Although with enough effort you can do that in Maven, too, by the time you get to the point where you understand how to do that, you know better. I can't even imagine what sort of nightmares somebody with the even-more unlimited flexibility of a bash script could conjure up.


I can see the attraction in a build system based on a proper full featured programming language but I've never been tempted to try gradle because I believe the approach has a fundamental flaw. I.e. that it's impossible for IDEs to reliably extract useful project structure from the build description.

Even as a 25 year vi/vim user, I've succumbed to depending on IDEs more and more and I believe that any proposed build system has to easily support deep/rich integration with IDEs. This is theoretically impossible if the build system is effectively a general Turing-complete programming language. At best you will be able to provide brittle integration or else the IDE will have to dumbly treat the entire build process as a black box.


The integration with IDEA and Eclipse for Gradle is actually quite good, the only downside is that it's "one-way". That is to say that you can't use the IDE's GUI to configure your build.

Gradle enables this as a first-class citizen by providing a "Tooling API": https://docs.gradle.org/current/userguide/embedding.html

I know that Buildship, the Eclipse plugin that integrates Gradle, is actually worked on pretty heavily by Gradle contributors. I don't know about IDEA but that's the IDE that I use for Java development and the Gradle integration is very, very good.


It is still not as good as Ant and Maven support, which allow two ways, and are even the project formats used by Netbeans.


I think that's a fundamental flaw of IDE's, they don't integrate with your development environment ;)

Something I just thought of but have yet to try, could we have a build script generate the project structure that an IDE can use and get the best of both worlds? Looking through my VS project files, 50% of it is stuff the make file would be doing, the other 50% is just a list of files and dependencies.

So let's say we generated these project files from a makefile, the IDE could still treat the build process as a black box but as part of executing that black box it gets all the information it needs for intellisense and debugging.


Both Maven and Gradle have plugins that will generate Eclipse and IntelliJ project files.

But also, both Maven and Gradle work by first building up a model of what the build will look like, then executing it. Gradle is complicated by the fact that it's much easier to run custom code that modifies the build during the build (which is why I don't like it so much), but IDEs can still inspect the build model to work out what's going on.


> Both Maven and Gradle have plugins that will generate Eclipse and IntelliJ project files.

So does this work as I suggested? Can you do whatever you want in you're build script and output something usable for eclipse?

> But also, both Maven and Gradle work by first building up a model of what the build will look like, then executing it

Isn't that pretty much what make has always done? You define outputs and what dependencies are needed for those outputs and make will work out the path to get there.


Make works on a files in -> one file out basis, and the IDE has no visibility of any other side-effects. That works for build systems with that property, but some of the interesting bits of builds touch multiple files. It's also why I like Make and Maven and don't think Bash and Ant make suitable build tools.

Maven and Gradle plugins also have the advantage that the IDE can be taught to understand what they do -- a Makefile can run a compiler, but the IDE can decide to use incremental compilation and update a debug target on-the-fly, as it can see what the project build is doing and replicate the results.

On the subject of generating project files, pretty much everyone I know prefers to use the IDE's tooling for importing build files rather than the build tool's tooling for generating IDE files. And that's probably a self-reinforcing behaviour as far as tooling quality goes.


I think it's not correct to say that Turing-completeness somehow prevents extracting project structure. If a build tool can extract that information, why IDE could not do that? In fact this is how Gradle projects are imported into Intellij and Eclipse: Gradle builds project model by running Groovy or Kotlin scripts, and then IDEs are working with declarative model. The real problem is working with scripts themselves: changing them automatically (applying refactorings), providing good completion, navigation, etc. The dynamic nature of Groovy makes it much harder for IDEs to provide good tooling, but even with statically typed Kotlin it is hard because Gradle APIs are very dynamic in nature (lots of string typed APIs). That does not mean that Turing-completeness prevents good tooling completely, it just requires more efforts and has some limits depending on a build tool`s software model.


To answer your question as to why an IDE can't do it, the reason is that in order to do it you need to solve the halting problem.

Of course, the IDE can do it if you limit yourself to a subset that is not fully Turing complete, which is what IDEA does today.

The issue a lot of people have with Gradle is that this subset is not well defined, and it's very easy to do something that works but will get the tools to have problems, and debugging such issues is not particularly entertaining.


IDE does not try to analyze Gradle scripts directly, it works with declarative model that is created by executing Gradle scripts. Gradle works in two stages: 1. Configuration: scripts execute and produce software model (DAG of tasks essentially). 2. Execution of necessary tasks in the graph.

IDE cannot get the graph by analyzing scripts, but it does not need to: instead it can ask Gradle for the model. The model itself has nothing to do with Turing completeness.


You're not wrong about the halting problem, but the reality is that most people do simple things that the IDE can extract a lot of information about. I.e. it doesn't have to understand a function to make the function fireable from a GUI button, and that is still actually quite useful.


Idea works fine with non-trivial Gradle builds. It might be theoretically impossible, but on practice it works.


This pretty much matches my experience. I resisted maven and the obscure pom.xml structure for a long time but eventually came around due to its excellent dependency management. Now that I understand maven it's hard to see how Gradle really improves on maven for basic Java projects.


Seems "obscure", but it has a schema.


Just to be clear, I'm not against XML at all. Maven does more but can be a pain to program compared to older systems like ant, which is also XML-based. Configuring plugins to fire at the right point in the build cycle (e.g., package vs. install) comes lightly to mind.

It's gotten a lot better because there are many examples now accessible with Google. Overall I'm pretty happy with maven now. It works.


"It's gotten a lot better because there are many examples now accessible with Google."

That is the main reason I am sticking with Maven (where practical). Examples, documentation, and answered questions are plentiful.

"Configuring plugins to fire at the right point in the build cycle (e.g., package vs. install) comes lightly to mind."

The official documentation has that covered well: https://maven.apache.org/guides/introduction/introduction-to...

An example they give is:

  ...
   <plugin>
     <groupId>com.mycompany.example</groupId>
     <artifactId>display-maven-plugin</artifactId>
     <version>1.0</version>
     <executions>
       <execution>
         <phase>process-test-resources</phase>
         <goals>
           <goal>time</goal>
         </goals>
       </execution>
     </executions>
   </plugin>
  ...
i.e. plugin "display-maven-plugin" should execute its "time" goal during the "process-test-resources" phase.

IIUC, there are no fixed phases in Gradle, so this sort of thing is done with task dependencies.


Well, excellent... their versioning is so broken that it had to become a de-facto standard to become accepted


Which versioning do you mean? Of Maven itself?


> "Great Flexibility. Highly customizable build. You can easily create your own task and do whatever you want."

Usually this is a red flag for me. People's apps really aren't that different, if you're doing some weird customization its going to be a nightmare for the next guy to maintain.


To me the beauty of Gradle is the complexity is hidden behind plugins so that the majority of builds are simple. I’d say a basic java build in gradle is simpler than the equivalent maven xml. The power is there for when you need it, but the basic plugins are easily configured for the basic stuff.


If someone wants customization, he'll do it. If build tool will be on his way, he'll write PowerShell script, generating Perl script using M4 and you'll live in a some special level of a nightmare. Gradle has a lot of plugins, so typical builds are possible just like Maven (there might be exceptions, of course), but if you need to customize something, I think that being able to write an ad-hoc task with Gradle is better than not being able to do so.


I delivered a session at JavaOne (2001?) on Ant (I was a whiz at it). Then, I had to learn Maven as it gained traction. I'm currently doing Android development, but I'm a little embarrassed to say that I don't really grok Gradle the way I do with Ant and Maven. I don't have anything against Gradle. I just don't want to spend another minute of my life learning another Java build tool. So, I stick to the Gradle defaults when creating a new project in Android Studio, and rely on SO and whatnot whenever I need to customize. Haven't been burned yet.


The biggest challenge for me when I started using gradle was understanding groovy. Once you get groovy, you get gradle. And I really like groovy now that I get it.


The whole article could be written about moving to maven. I still have no idea about how to do even trivial modifications to maven builds without googling them.

Fwiw, the need to learn groovy is a bit of a red herring because it doesn't help that much: I know groovy very well but I still find gradle confusing and have to google everything. My favourite build system of all time was gant, also based on groovy but a simple wrapper for ant. It had zero magic, was just a systematic wrapping of the ant API which itself was just a bunch of well documented useful build utilities. I found it very easy to use. The contrast between two build systems both based on the same dynamic language was very stark to me.


> Gradle features: Great Performance

Did I missed the sarcasm tone? I've never experienced slower build systems then those used in Java world, like Gradle for example.


Are you talking about Android? I'm using Gradle for traditional Java projects (standalone and web) and its performance was good, similar to Maven. I agree that Android plugin is very slow, but I think that it's not a Gradle to blame.



People complain about C and C++ compile times but they don't hold a candle to that in Android-Java-land in my experience.


Yep, specially when you get to join NDK and Gradle builds.

It is not time for coffee, rather lunch.



I’m surprised nobody has mentioned buck or bazel in this thread.

At Addepar a few years ago, I transitioned a several-100-k LOC Java codebase from Gradle to buck. It was a fairly complex build including Jooq code gen.

Build times became much faster and flaky CI issues went away.

Today, I’d try Bazel— Buck only exists because ex-Google FB engineers had to recreate Googles amazing Blaze build system. Google has since released much of the original as open source, renaming to Bazel.

Maven and Gradle are both flaky, slow, and annoying to configure, in my experience.


I would have used Bazel (or Buck) at Addepar instead of Gradle had either been released (I really loved Blaze). The transition from IDE-only to a standard process was painful, as you remember.

I'd like to use Bazel (or even Buck) these days, but no bandwidth given other projects. I always felt modules were a mistake compared to a single large tree, which Bazel does elegantly. Sadly my familiarity with Gradle is much more than Blaze these days, and I'm too exhausted to do it just for fun. I think there is also a bit of Stockholm syndrome at play, since I convinced myself it was not too bad back at Addepar.


Oh hi! Hope things are well!

Not hating on the Gradle setup at all — it made sense at the time.

I also like the tree approach, it feels clean. Plus the hash cache to avoid rebuilding things when nothing’s changed—faster and more robust than tools that use mod time.

I’m going to try Bazel soon at Dynasty. (We’re on ant now lol... but with very simple build, so it isn’t too bad.) I’ll let you know how it goes.

LMK if you’re ever in socal!


Because in the Java world no one really cares about Bazel.


I went back to maven. I had trouble finding solutions to gradle issues when I got stuck. Maven solutions are easier to find. This will probably change as gradle becomes more popular.

I should add that I am no Java guru, so for me this is an important consideration. Still, the real Java gurus at my company are split on the issue. We have projects on both build systems.


One thing I haven't figured out in Gradle is that (in IntelliJ) in a maven pom, I can command-B to find the pom definition of a parent pom or a dependency. command-B in gradle doesn't do anything there. Anyone know the magic command?


Asking the real questions.


We're planning to add a Maven compatible artifact repository to GitLab. I assume that will automatically also work with Gradle, or is there more to it?


Yep, you can publish to a maven repository from Gradle pretty easily. I just setup a project to publish from gradle -> artifactory last week.


Cool, thanks!


Recently I need to maintain a gradle script written by others. He created a Copy task, but he deleted some files inside. Every time I execute other tasks (not his task), those files are deleted. Finally I found that I need to create another Delete task and make a dependency to his task. I still don't understand those "doLast" thing very well.


When I think of Gradle I think of the countless software development shacks where no one can understand or extend the Gradle configuration because someone, years ago, thought it would be cool to be hip and use Gradle instead of Maven, left the company and now nobody is interested in learning it.


Probably unrelated, but Java really needs to fix its Classpath Hell issues. On so many sufficiently large Java projects, you end up descending into the inclusion/exclusion madness with your build files because your app is inheriting `log4j` from 50 different libraries. Or the infamous xerces hell[1]. And fixing that in maven is not pretty :(.

[1] https://stackoverflow.com/questions/11677572/dealing-with-xe...


I hit this just recently with an in-house dependency injection library. We upgraded the version in an application, it worked great, we deployed it to a cloud environment. Lo and behold the application wouldn't start up, and more importantly wouldn't give us a real reason why. In the end I discerned from cryptic logs that it was because Java had loaded up both the jar of the version we wanted and the jar of an older version that happened to be in the classpath too. You can't have two dependency injection systems running at the same time, so they fought and came to a stalemate. Deleted the bad version and it was all good.

I know that this isn't entirely Java's fault, as that second jar shouldn't have been there to begin with, but it's pretty ridiculous that two versions of the same dependency can be loaded and in use at the same time.


Wasn't Java 9 modules supposed to help address these issues?


No, it is supposed to reduce surface area between modules/jars. Before Java9 library creators could only add "internal" to their packages name and hope end users won't touch it.

The introduction of modules might actually make version hell even worse: https://blog.codefx.org/java/dev/will-there-be-module-hell/


The advantages/drawbacks section could easily apply to Java as a language itself as much as to Gradle. Flexibility and performance traded for unending complexity, all-encompassing scope (creep), and the subsequent unpredictable behaviour/side-effects which the latter creates.

Which makes this backlash entirely unsurprising because the mainstream foundational tools will eventually end up reflecting the culture of the programming language, given enough development time and an unconstrained mandate seeking to keep the wider community happy.


The problem with build systems is that people try to do too much with them.

It wouldn't be so bad, if there was consistent, thorough documentation available, including for the various plugins that people put together and shared.

But where things stand it's entirely too easy to have builds that only a few people really understand as they read through the build definitions.

At their heart, builds are simple. Pull in dependencies. Process templated files. Copy files. Run a test suite. Compile/link/etc.

Yet, with large projects there always seems to be something unique that requires a custom plugin or a day and a half trying to figure out how to move a particular step, or heaven forbid running the same kind of step twice at different stages.

The way I see it - if you have to spend a day figuring out how to do anything with your build system, you have eliminated the benefit of said build system. You might as well build a shell script in half an hour that does what you want it to do. If someone can come along later and say "that's easy with ant/maven/gradle/buildr/make/etc." and can throw it together quickly along with a quick doc explaining the steps, then fantastic.

I think time is better spent writing software than struggling through learning a build environment.


Given that Gradle is here to stay... Can anyone share good resources for understanding Gradle?

With complex Makefiles, at least you have the sources and can try to understand the logic. With Gradle, it's all tons of compiled java code.


As someone with extensive exprience with both, my opinion is that Kotlin will greatly tip the scales in Gradle's favor, and I'll probably switch to that as my preferred choice for non-scala projects


What about the performance benefits (ie, incremental builds being broken in Maven)? EDIT - to clarify - has anyone found a way to make Maven just as fast?

We have Maven builds that can take an hour and Gradle drops that down to minutes (or less than a minute).


I work on full-stack product, with iOS/Android SDK element that other people integrate in their apps. Server-side with UNIX boxes: everything works always.

Xcode/iOS: we published CocoaPods. It was pain to get to work reliably on laptops/Jenkins b/c of upgrades to Ruby, but if you lock yourself to one Ruby version, and lock the Gemfile, it's mostly OK. At least it's pretty obvious when/why it doesn't work.

Gradle: it's such a mess. I don't even know where to start. I don't know Maven, but Gradle error warnings are the worst. 4 lines, tells you nothing, with turned on debugging the output tells you nothing, while e.g.: in reality you don't have the child-repo checked out because you forgot to `git submodule update --init`.

Getting Gradle to work on a laptops across the team of 4 was a pain. We had cases where two people with the same AS version and the same gradle version couldn't import the project into AS. Our instructions are - after 'git pull' make sure you do 'git clean -dfx' and re-import the project.

Personally 50% of time when I start Android Studio I have some critical exception of some sort, each time from Gradle window. There's this, plus gradle wrapper. I pretty much never worked for me. This is meant to solve problems with always getting you the right Gradle version, but this is sci-fi. I believed it's just me who uses SDKMan to be able to fetch the right gradle which our project depends on, but others around do too. Otherwise it's a pain in the ass -- and `brew` doesn't have the gradle's we need, because they migrated to the very latest one, when in production you'd rather have older version for an extended period of support time.

If you, just like us, have a project which has 3+ years of scar tissue and it has to integrate with javanet, picasso, okhttp, volley etc. and you have several people who fetch and integrate your code in their apps--I feel really, really sorry for you.

DSL is all right, and maybe Groovy has some unique features, but I never discovered them. This is Java language that isn't Java, or some dialect of Java-like language aimed to make Java 3% better, but to be honest I don't hear people writing Groovy for fun and pleasure. So to me it was a cost of learning basic stuff just to be able to automate simple stuff in Android build system (when we run ./jenkins.sh --local, we want our Android functional tests to hit local dev environment). Of course in XCode it works 100% better and took 20% of time to do, since Apple owns XCode and made it look better: go to project settings, drop in the path to post/pre built scripts to customize your flow, and in a language you already know. Google, who subleases Android Studio from JetBrains, had no choice and made Android ecosystem look like a Frankenstein.


> I don't hear people writing Groovy for fun and pleasure.

It was common at local JUGs almost 10 years ago, when there was lot of hype around Groovy and Grails.

Even at JSF Days 2007 there were some talks about adding Groovy support to JEE as a means to write session and entity beans.

Nowadays Gradle is the only thing keeping Groovy from completely fading away.

That and Grails maintenance projects.


We moved to apache buildr years ago and never looked back.

https://buildr.apache.org/


Funny that, because I spent 3 months removing buildr and adding maven on a large, complex project. After a couple of years into buildr, the build had grown so artisanal that even breaking a jar out of one of the build's modules was a multi-week task. After we moved, multiple modules were made into jars and some even wound up becoming external projects very easily.

Everything was done in scripts (predictable when you offer nothing else) and it was so misconfigured and esoteric that nobody happened to notice that it was reaching out to the wrong server for artifacts....WHOOPS!

Dependency management was awful and g'luck even getting something as simple as a dependency tree out of the system. Oh and it appears to lack any mindshare so nobody appears to be improving it and g'luck if you happen to need some help with it.

The problem with buildr is that it's a ruby based build system for Java. Why? Who wants to write their Java build code in Ruby, and why can't they just go work in a RoR company already?

Builds shouldn't be interesting, artisanal, or occupy a lot of your time. They should just produce the artifacts and move on.

Since the switch to Maven I find myself worrying about the builds a lot less and actually working on code instead.


Maven’s approach is a lost cause: you either expect any user to coerce their case into your model (and hope the plugin is documented, dependencies work (bwahahaha) and is maintained) or you breakout to some exec plugin and give up on platform agnostic builds.

Sure, it’s an unforgiving ambition and many other systems fell trying, but it was their choice.

With Gradle the blame falls squarely at the feet of plugins, and you’re on your own (which has always been the case anyway)


> you either expect any user to coerce their case into your model (and hope the plugin is documented, dependencies work (bwahahaha) and is maintained)

I find all the cases can be coerced, and it's not even hard. Some users seem to insist on customization for its own sake, "oh I absolutely must call my source folder source rather than src", but Maven does the right thing by ignoring those users, with the result that you can pick up any project that uses Maven and be immediately productive.


The case I remember was a couple of years ago. We had a test runner for our JS code that was delivered by our Java webapp. Part of that configuration was the list of flags to a maven plugin. The issue was that we had two orthogonal configuration options that affected the list of flags. Initially, it used HTMLUnit and didn't record coverage statistics. We wanted to record coverage, and also switch to PhantomJS (when it was new) over HTMLUnit. Our test times were as follows:

PhantomJS - 1 min

PhantomJS + Coverage - 5 min

HTMLUnit - 10 min

HTMLUnit + Coverage - 25min

Coverage required one set of additional flags, PhantomJS required another. But we could only replace the test runner string, not add to it. We couldn't drop HTMLUnit altogether, as our company mandated CI system would not make it easy to install PhantomJS. And tests were still new to many team members so if we defaulted coverage on, nobody would run it with those times. So ideally we'd have mvn test -Pphantomjs -Pcoverage if we wanted phantom with coverage. But actually we had to do mvn test -P{phantomCoverage,htmlUnitCoverage,phantomNoCoverage,htmlUJnitNoCoverage} which meant copy pasting a substantial chunk of our pom file 4 times to change two lines of it, rather than a base case with two overrides.


Ok, good example of the tradeoff maven makes. My view is: it's worth making that kind of inherently complex case complex for the sake of the comprehensibility advantage that all projects gain from having the entire test runner string in one fixed place where a reader can look for it. Some test plugins do provide a separate "extraArgs"-type config that you can use for that kind of case, but I'm not convinced that it's a good idea.


I'm not sure what's your point, but Maven allows to change source folder very easily. Maven has sensible defaults, that's right.


I've used both; ant as well in the distant past. More gradle than maven lately but I still have a few maven projects. True for both is that you don't want to push them beyond simple stuff. It just gets ugly and most of your team will look the other way when it is time to sit down and fix the build (usually that job lands in my lap).

There are maven and gradle plugins for just about everything and it is tempting to use them but your build files will quickly become very complex and unmaneagable. Worse, a lot of these plugins are poorly documented, if at all, and tend to not add a lot of value. And that's before you start hitting the corner cases, bugs, and left as an exercise to the reader type stuff that just requires copy pasting bits of half working stuff from all over stackoverflow. Once you go down that path, maven and gradle are equally frustrating.

Solution in both cases is to simply not even try to do everyting in a build file and fall back to simple alternatives: use a small run.sh instead of trying to get some unholy maven xml blob or gradle script to fork off a jvm just right; really a script is a lot easier to write, maintain and it does exactly what it says. And even better, you get to reuse it in the last line of your Dockerfile where you start your software.

Speaking of Docker, packaging things up as a docker image (or rpm, or whatever), is also definitely out of scope for build files. I'm sure it is possible to do with some unholy combination of craptastic plugins in both; but why even bother? Just use a Dockerfile and docker build for that. They are nice and simple and any decent devops person knows how to work with them.

Actually, in some of my projects the whole build is a docker build. It's great! I let it take care of downloading the jdk, gradle/mvn, and then let it download the world as a separate docker layer before letting it build the software. Most of the builds it jumps straight to building software unless I touch the build file. Also makes for really simple CI: all your build server needs to know is docker. Also people can build and run your software without installing anything else than docker (and git, and maybe a few other bits and pieces). Add some docker compose and you can do integration tests (another thing that you should not attempt from a build file).

Also, with both maven and gradle: avoid multi module setups. They slow down your builds, multiply your complexity, and all for the illusion of not quite having reusable components. Once you have two modules, you will need three, and four, etc. There's no end to it. Just don't. Usually you are just looking at Conway's law in action: it rarely buys you anything but misery and slow builds. KISS & YAGNI.


> I let it take care of downloading the jdk, gradle/mvn, and then let it download the world as a separate docker layer before letting it build the software.

Including your source code inside your Docker image unnecessarily inflates the size of your Docker image, including (seemingly from your description) the entire version control history. For big projects (especially big projects where junior engineers didn't get the memo that you shouldn't check binary files into Git...), this can easily add hundreds of megabytes if not gigabytes to the size of the image.

Docker isn't a build system (which is responsible for the creation of both inflated-but-easily-debuggable as well as optimized-for-production), it's a combined packaging system and runtime.


I've used Maven, Gradle and SBT in major commercial projects. I don't understand this Maven love honestly. Maybe everything I had to work on was just setup incorrectly, but the horrid overly verbose xml configuration files combined with the fact that maven constantly recompiled things it didn't need to and was sooo slow.

I think the only good thing from Maven was the directory structure layout (src/{main,test}/{java,scala,groovy,resources}) which has carried on to other build system. I didn't like that at first too, but I've since come around.

SBT does a lot of things really nicely if you're in the Scala world. `sbt console` is wonderful. That being said, never take up the sbt source code and try to hack on it. That's a disgusting mess under there. Also the whole task dependency/macro structure can get pretty awful when you want to run tasks with multiple configurations in one go. I don't think it's possible. The sbt-native-packager works really well, but once again, that source code will make you want to throw up. At least back in like 2014 it did. Who knows. Maybe it's gotten better.

Honestly all the build systems are kinda terrible, but I'd take groovy or sbt any day over maven. I don't see how anyone likes it. Trying to figure anything out in Maven was just miserable.


We love it, because not everyone suffers from XML allergy, which is way more toolable and easily integrated into IDEs than tools using the programming language of the day.

Ant and Maven just work on IDEs and on Netbean's case, they are even the official project format.


Concur. I found Gradle to be to far removed from the truth so to speak. I like Maven's declarative xml and its promulgation of the build life-cycle. This makes a complex build easier to maintain in the long run imo.


Because you don't know Groovy. Simple.

Maven it's only in your comfort zone. Bye.


Gradle scripts are an undocumented superset of Groovy. It's not just Groovy, it's the fact that there's no consistent way to know what settings and defaults come from where.

(And really, why would you know Groovy these days? Is it even used for anything outside of Gradle anymore?)


Groovy is super useful for JSON mapping, objects without boilerplate, spock mock testing, etc. I love it because you can be as loosely typed or as strongly typed as you want depending on the code you're writing.

I don't see a reason to NOT use groovy in any java project. It makes java so much nicer.


* Easy to read * Collections tools * Functional programming with closure * Traits * Typed or not * DSL * 100% compatibility with all jars * Awesome framework like Grails and the upcoming Micronaut and SpringBoot * Enterprise software or script, you're welcome.

There is a whole world out there.


Yeah, time travel to JUG meetings 10 years ago.

Nowadays all of that is a synonym to Grails maintenance projects.


Groovy is actually an extremely useful language to know. Something approximating bash for java, but with capability to scale up to full application development. Gradle would be one of the less important reasons to learn it imho.


I mean objectively it's not a bad language for its era, I just never found a compelling reason to use Gradle rather than something else. When I started out on the JVM I used Jython for scripting tasks since I already knew Python, and once I started using Scala I used that for, well, everything really.

I don't want to get too deeply into language wars, but Java, Python and Scala all have "killer" features, things they offer that no other language does - you may not agree with them but there are reasons someone might pick that language over every other language in the world. Whereas Gradle just felt like "it's a Python/Ruby/Perl-like language that runs on the JVM" - if there's something Gradle's actually the best at, their communication failed to convey it.


> Whereas Gradle just felt like "it's a Python/Ruby/Perl-like language that runs on the JVM" - if there's something Gradle's actually the best at, their communication failed to convey it

I assume you meant groovy there. But yes, I remember actually posting exactly that view on here several years ago! I felt that if I was going to learn a JVM language, why not invest that effort in something that was more generally applicable or has broader benefits, and kill two birds with one stone? I deep dived into Scala, and looked into Jython, JRuby and other JVM languages. What I came up against every time was that each of those languages seemed to have significant impedance mismatch with the JVM. I found I really wanted something as close to Java as I could get but with a scripting programming style so that I could do quick experimental coding. For me that is where groovy beat everything else. As I used it more I started building larger projects with it because it scales up pretty well. So I often build about 70% of a project in groovy and then do 30% in Java where I want the real static typing (interfaces, domain model, etc.).

This seamless interoperabiity with Java/JVM is a fairly subtle selling point especially since every JVM language will say they do it. It's only when you try to use them in complex projects and see them fall down that you realise that groovy is the only language that is philosophically trying to be close to Java (I'm fairly keen to try Kotlin to see how that holds up on this count).


> This seamless interoperabiity with Java/JVM is a fairly subtle selling point especially since every JVM language will say they do it. It's only when you try to use them in complex projects and see them fall down that you realise that groovy is the only language that is philosophically trying to be close to Java (I'm fairly keen to try Kotlin to see how that holds up on this count).

Interesting - can you say anything more concrete/specific? E.g. with Scala I've gradually drifted away from a Java-like style over the years, but I found it was very possible to write in a close-to-Java style (e.g. using the Java collections rather than Scala ones, using mutable vars and null and subclasses) when that was what I wanted.


You could be talking about Apache Groovy's seamless interoperability with Java 7. It hasn't kept up with Java 8 and lambdas, let alone Java 9 and modules.


It's still far more seamless with java 8 than any other language. I don't care about superficial syntax similarity, that is not really the point. Nicer interoperability with java streams would be good though.


Yes, it's of course used in Grails. I'm also a fan of Spring Boot + Groovy.


Not really - or, at least, not that simply. When my last organization moved to Gradle, and we had a Gradle ninja go in and migrate all of our build scripts to hundreds of lines of Gradle scripts, I thought the same thing. So I spent a month on-and-off studying and learning base Groovy (fending off coworkers who would pass by my desk and ask, "what are you doing?" "Learning Groovy" "Why are you learning groovy?" "So I can use Gradle" "Why do you have to learn Groovy to use Gradle, Gradle Ninja already did it for you"). I finally got to where I was, if not an expert, at least comfortable with core Groovy. But even then, there was a lot more to Gradle than just "a build script written in Groovy" - there's another learning curve to climb once you've learned Groovy.




Consider applying for YC's W25 batch! Applications are open till Nov 12.

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: