GlowstoneMC / Glowstone

A fast, customizable and compatible open source server for Minecraft: Java Edition
https://glowstone.net
Other
1.9k stars 273 forks source link

Gradle building #975

Closed Zaxar163 closed 3 years ago

Zaxar163 commented 5 years ago

Why Gradle is better then Maven? It has easy plugin interface and flexible build scripts. You can write custom tasks and include scripts...

--- Want to back this issue? **[Post a bounty on it!](https://www.bountysource.com/issues/65905608-gradle-building?utm_campaign=plugin&utm_content=tracker%2F14691067&utm_medium=issues&utm_source=github)** We accept bounties via [Bountysource](https://www.bountysource.com/?utm_campaign=plugin&utm_content=tracker%2F14691067&utm_medium=issues&utm_source=github).
mastercoms commented 5 years ago

Although we can, do we need to? A declarative build system like Maven is simpler and gets the job done, fast. We don't need a build language to handle our builds.

hazae41 commented 5 years ago

Although we can, do we need to? A declarative build system like Maven is simpler and gets the job done, fast. We don't need a build language to handle our builds.

Simpler? Glowstone build is done with about 400 lines of Maven while it could be done in about 100 lines of Gradle

Fast? It has been proved that Gradle is between 10 and 100 times faster than Maven

Not knowing how to use it doesn't mean it is complicated ;)

aramperes commented 5 years ago

@Hazae41

mastercoms commented 5 years ago

Speaking of performance, Glowstone specifically was much slower on Gradle compared to Maven. Maybe gradle.org has a bit of bias?

smartboyathome commented 5 years ago

Just wanted to add one other reason for sticking with Maven right now. Currently, we're using Maven's dependency resolution internally for our runtime library dependencies. If we moved to Gradle, this would probably also need to be moved as well in order to keep the dependency resolution consistent. between both systems. That would likely be a sizeable amount of work for very little gain, so I would also recommend against moving.

Pr0methean commented 5 years ago

@Zaxar163 If you're still convinced we should be using Gradle, we'll consider a pull request with a complete implementation. But it must address @smartboyathome's comment (i.e. it must replace Naether with a Gradle-based counterpart).

aki-ks commented 5 years ago

Linkstone uses our own Maven plugin. If we switch to Gradle and want to stay consistent between all repos, we would have to rewrite it.

gdude2002 commented 5 years ago

WARNING: Super big comment (10,000+ chars). Caveat emptor.


I'd like to reopen this issue for further discussion, as a Gradle user myself - and the person in charge of devops (and, in part, continuous integration) for Glowstone. I don't feel like the issue as presented above provides an adequate summary of Gradle's benefits, or why either build system may be better suited to this project.

I am here to make the case for Gradle, of course - but I'd love to see some responses. If you disagree with me, please explain why!


What Is Gradle?

Gradle is a build system that takes cues from both Ant and Maven, and it attempts to improve upon both of those systems. Instead of using a declarative markup language (XML in the cases of both Ant and Maven), it makes use of a build script - usually written in a DSL based on Groovy.

DSLs, or Domain Specific Languages, are languages created to solve the problems presented by the specific domain they target. Gradle's DSL was designed with building projects in mind, including continuous delivery.

In this essay, I am calling upon several sources of information, along with my own experiences and the experiences of the Glowstone team, as we've worked with Maven over the years.

Advantages Of Gradle

Gradle is designed to iterate on the tools of the past, and to avoid the mistakes they've made. It makes use of Maven repos and dependencies (as well as Ivy repos and dependencies), so you can use all the same libraries. It's compatible with Ivy metadata, allowing you to define custom rules to specify a version for a dynamic dependency, and to resolve version conflicts. It can directly make use of Ant tasks, if that's your thing. It uses a Groovy DSL which was designed for the task at hand, resulting in much, much smaller units of build logic to consider. Don't like Groovy? Use Kotlin instead!

Gradle is built to be fast, and has much better support for dependencies...

Some other considerations...

So, What's Up With Maven?

Having spent some time working with Maven already, I can say that it's a fairly capable tool that is well suited to small projects. That said, I have run into a number of hang-ups...

Amusingly, a lot of developers today describe Maven as a "necessary evil". Maybe someone should introduce them to something else!

Further Ramblings

I find it interesting that the Glowstone project is currently using Maven - as it happens, the project was using Gradle when I first encountered it! I'm still not really sure why this change happened - even though it's been explained to me in the past, I just can't get it to stick in my mind.

There is obviously some debt that comes from changing build system. There will be a lot of things to figure out. Time will need to be taken to rewrite our current build logic. CI builds will need to be updated. For that reason, I propose that a change like this should wait until after Glowstone's 1.13 builds are released. That said, I do think investing the time is worth it, and I'm willing to spend time on this task myself.


If you got this far, congratulations - and thanks. Gradle has a lot more to it than the stuff I outlined above; these are just the features that I find useful and that I think could be relevant to Glowstone in one way or another.

I'd love to see some responses to this. Do your worst!

smartboyathome commented 4 years ago

So, I looked into why Glowstone swapped from Gradle to Maven so long ago, as gdude remembers. Back in January 2014, SpaceManiac first moved Glowstone to Gradle. This was back in the 2.0 days, when Gradle was rapidly adding features and not focusing on performance. So, in April of 2015, the Glowstone++ team decided to move back to Maven in order to speed up the build. They didn't know it at the time, but just one month later in May of 2015, Gradle would have their 2.4 release, which would speed up build times by upwards of 80%. So that is why you remember Glowstone using Gradle, then switching back.

With all that said, I will be looking into Gradle further, as someone familiar with Maven. I may take up the role of opposition, just to make sure that our decision is well rounded.

birbe commented 4 years ago

I second this idea, Gradle really is much faster in many cases and as 1.13 is highly unstable and (as of now) not even starting, the ability to make small changes rapidly is extremely important to the workflow IMO.

mguymon commented 4 years ago

Author of Naether here, I was dusting the cobwebs off of the repo a little and stumbled up on the mention here. There is no reason Naether could not work with either Maven or Gradle builds (originally it was used in Buildr).

Under the hood, Naether uses Maven's dependency resolution framework (albeit an old version of it), but that is independent of the actual build as is just a dep of Naether itself.

smartboyathome commented 4 years ago

WARNING: Another super big comment, following up on @gdude2002 's super big comment. No TLDR here, you really should read both his comment and mine in their entirety.

Now, as said above, I am going to be taking the role of of opposition on this issue. My reasoning for this is that I want us to make sure our decision is well rounded before deciding to switch away from it. After all, a bad decision can hurt as much as not making a good decision. Ultimately, though, I will respect whatever decision is made here, and I hold no ill will against Gradle or anyone who uses it. After all, it is quite a nifty build tool!

With that out of the way, let's get on with the discussion!


A History of Java's Build Tools

It is good to understand how we got here, and to understand why tools came into being. After all, those who don't understand history are doomed to repeat it. So, follow me on atrip down memory lane.

GNU Make

At first, there was GNU Make. Make could run shell commands, and used Java's command line compiler to compile Java code. It was designed to be generic, able to operate on a multitude of languages including C and C++. However, make was never really a Java build system, and rather quickly, devs found they needed newer tools to help take some of the pain away.

Apache Ant

Lo and behold, in 2000, Ant came onto the scene, becoming the first of the modern Java build tools. Ant's goal was to have a low learning curve, allowing devs to easily pick it up and start working quickly. It also provided a large amount of control over the build process, with the ability to include shell commands, logic, and plugins into your build scripts. When dependency management became needed, Ant adopted Apache Ivy. And, above all, Ant allowed you to write your build scripts procedurally, just like a programming language.

However, that wasn't to say Ant didn't have its issues. Its XML configuration files proved a poor fit for a procedural language, being hierarchical in nature. In addition, its files were very verbose, getting out of control very quickly if care is not taken to keep them consistent. Being procedural, any parallelization and optimization was up to the build script writers.

So, yet again, another tool was needed...

Apache Maven

Maven came onto the scene in 2004. Its goal was to improve upon Apache Ant, and standardize the untamed, verbose files that it generated. To do this, while keeping its XML file format, it switched from procedural to declarative for its build files. Gone were the days of needing to meticulously order and code your build steps, instead you could just bind the plugins directly to different phases of the build and Maven would take care of the rest. Most importantly, Maven introduced dependencies as a first class citizen, before Ant's adoption of Ivy.

But, Maven had problems of its own. Because it was based on XML, build files still usually ended up being fairly large without doing that much (although still less than Ant). Because of its declaritive model, flexibility was lost, instead opting for a clean separation between custom logic, in the form of plugins, and build steps.

As time went on, newer languages came into existence, and with the rise of languages like Ruby, came the rise of DSLs. Wouldn't it be nice if Java had one of those for its build tools...?

Gradle

The newest of the major Java build tools, Gradle came onto the scene in in 2012. Building on top of Groovy, which took heavy inspiration from Ruby, it defined its own domain specific language, taking ideas from both Ant and Maven. It built upon Ant's power and flexibility, using a procedural language to allow rich build scripts, while adopting Maven's ease of use and lifecycle management. Build scripts could be made much shorter than either Maven or Ant, and as time went on it gained incremental compilation and caching, giving it superior build times.

Up to today

So that's where we are today. Apache Ant has mostly fallen out of favor, leaving Maven and Gradle to compete for use by Java's programmers.

Maven's Advantages

As both gdude and I pointed out above, Gradle attempted to improve on the tools that came before it, and for the most part succeeded. But, that doesn't mean Maven has no advantages whatsoever. Gradle's never quite managed to kill Maven off, unlike Maven did with Ant (for the most part). Why is that, I wonder? Let us see...

To rebuke some of gdude's points above:

Conclusion

I am really not trying to attack Gradle here, despite having a lot of negativity here. I just feel like Maven's getting the short end of the stick in this discussion, and that Gradle has brought back some of the mistakes that Ant had made. Don't get me wrong, Gradle has quite a few nifty features that I like, including incremental builds (although I wish it weren't tied to a daemon). I am but a developer, though, and not maintaining a lot of infrastructure like gdude is, so Maven works just fine for me in most projects I create.

But, this is all I can write for now. Like gdude, I'd love to see more viewpoints around this.

smartboyathome commented 4 years ago

Oh, and thanks for the input @mguymon . I only learned the other day that internally Gradle uses Maven's dependency resolution, so I am perfectly fine to keep using Naether if we move Maven over to being built with Gradle.

smartboyathome commented 4 years ago

One more point to add on to above:

gdude2002 commented 4 years ago

While I have a little time, I've got a few counterpoints to the above comments.

  • Maven, like Java, has been designed to be incredibly stable. Indeed, most plugins don't have to worry about which version of Maven they're targeting, as Maven vary rarely makes breaking changes. This stands in stark contrast to Gradle, which makes breaking changes every year or so, forcing plugin developers and script maintainers to constantly chase them.

This is really a non-issue; there's nothing stopping us from picking the Gradle version we want to use and sticking to it - indeed, most projects stick with a fairly old Gradle today. The canonical way to use Gradle is via the Gradle wrapper, and you pin a Gradle version as part of setting that up.

As for Linkstone development, I'm not convinced that a plugin of that calibre will require many version-change fixes.

  • Maven's dependency system is still very widely used, so much so that any even slightly popular library will be published to Maven Central. Most organizations will use some form of Maven repository, and many hosted cloud providers support managed private Maven repos.

This doesn't really have anything to do with anything - Gradle has full support for pulling from and publishing to Maven repos, and it does it in a much friendlier manner than Maven itself.

  • Maven's build scopes are incredibly well defined and easy to understand. For small- to medium-sized projects, they may never even need to define any non-standard logic or build steps, so its fairly easy for many to figure out what's going on in their build script.

I don't really understand this from the viewpoint of Maven vs Gradle - they both have very well defined build scopes. In addition, it's extremely easy to define a custom build step with Gradle. Here's an example from another project I've worked with that uses Webpack:

task webpack(type: Exec) {
    inputs.file("package-lock.json")
    inputs.file("webpack.config.js")
    inputs.dir("$projectDir/src/main/js")
    inputs.dir("$projectDir/src/main/css")

    outputs.dir("$projectDir/src/main/resources/assets/journeymap/web/bundled")
    commandLine "npm", "run", "build"
}

tasks.processResources.dependsOn webpack

This fully supports Gradle's incremental build system and build cache, as well.

  • Maven does not require learning a completely new language, unlike Gradle.

While this is true, the language doesn't have to be Groovy - indeed, Gradle supports a Kotlin DSL right out of the box. Considering how well Kotlin pairs with Java, and how excellent the IDE support is for it, it seems like a good match (I didn't really understand the comment about lacking IDE support - IDEA's support is amazing, and Kotlin is new enough that other editors aren't going to have caught up yet). Additionally, there are tentative plans to rewrite Glowstone in Kotlin at some point in the future.

  • Maven's XML is well structured, making it very easy for IDEs to provide rich autocomplete and documentation support for it. Groovy, being a dynamically typed language, cannot positively support such static guarantees

Agree - but we have Kotlin. See above!

  • ...As long as plugins play by Maven's rules, and the user learns about its build scopes, Maven becomes almost like building blocks that you click together to create your build.

This comment doesn't make sense to me, given that Gradle basically feels the same way. You have a set of tasks which depend on each other, and you can easily manipulate which tasks depend on which other tasks - which provides a fairly simple way to build your task tree.

That said, 90% of projects will never need to worry about this.

  • Maven does support uploading already-built artifacts into a remote repository. Maven does have a problem where each build is not idempotent or reproducible by default, but there is a guilde and a plugin that each solves this problem in slightly different ways.

This should not be a plugin. This should be a core part of the build system. It should be smart enough to understand when a full rebuild needs to be done, it should be able to skip rebuilding and use the artifacts in-place using a simple switch, and it should support reproducible builds by default.

  • Gradle's compilation efficiency is really only available on development machines, where caching is able to carry over the results over time

Agree - but the vast majority of the time, development is where you need that speed. Gradle's daemon and build cache allow for fully incremental builds, and this can make testing changes very quick indeed.

  • While Maven promotes the attitude of "good enough", Gradle has never really lost its attitude of constant change from its early days, forcing users to try to chase the latest major Gradle versions. Due to this, a Gradle build from 3 years ago is very unlikely to run, while a Maven build from 10 years ago will still work just as well today.

Genuinely, this is not true at all. See my above comment relating to the Gradle wrapper - pin a version, and use it. That is the correct way to use Gradle.

I'd say it's an advantage, to be honest - you never have to have Gradle installed at a system level at all!

It's probably worth pointing out that Gradle easily supports many other languages and types of builds. If we needed to bring builds involving more than a JVM language to Glowstone, Gradle would be the best way to do it.


While polyglot-maven is an interesting project, there are many other concerns that I have and they are simply not addressed by a change in definition language.

aramperes commented 4 years ago

I have little to add to discussion here. However if someone wants to try their hand at converting Glowstone to Gradle as a proof-of-concept, and can demonstrate shorter build times, I'm all for it.

smartboyathome commented 4 years ago

The more I have learned about Gradle, the more I understand its philosophy, and how it is drastically different from Maven. As I indicated above, while they both try to achieve similar goals, they both approach things very differently. Indeed, Gradle is much more of an alternative to Ant, with many fixes and modernizations, than it is a Maven alternative. This is why both have been able to coexist, while Ant itself has been fading.

One final thing I wanted to address:

I don't really understand this from the viewpoint of Maven vs Gradle - they both have very well defined build scopes. In addition, it's extremely easy to define a custom build step with Gradle.

Let's be clear here, Tasks in Gradle are not like scopes in Maven. Configurations fill a similar role to scopes in Maven, allowing you to specify something to be included only at compile time, run time, etc. Tasks are closer to Maven's build phases, but even those aren't very comparable.

Speaking about phases, in Maven, as you said, its phases are strictly defined and you cannot easily insert a new phase very easily. When you include a plugin in your maven build, you can optionally specify which phase it will run in, or defer to its default phase. Maven will take care of ordering all plugins within each phase,so that the developer doesn't have to worry about it themselves. But, at the end of the day, all you can do is bind plugins, so any custom logic you want to do requires creating a new plugin.

This stands in stark contrast to Gradle's Tasks. With Gradle, you have to chain tasks to each other, and it provides no default "buckets" in which to hook tasks to out of the box. This gives immense flexibility, but in this flexibility you need to read more of the build script in order to understand it. Being able to define your own tasks inline is indeed very powerful, and is sometime I sometimes needed when working on Node.js projects that used Gulp (a very similar task runner). When you do need this, it can speed up development work immensely because you don't have to go through the process of getting a new library spun up.

But, its this ease which worries me, as it is where I have seen the most stumbling blocks with Ant, requiring me to dig into plugins to understand exactly where things need to be hooked together. I'm not saying that Gradle hasn't improved upon this, but at the end of the day creating an easy to understand Gradle build script feels like its a bit more of an accomplishment than creating an easy to understand Maven POM. There is the familiarity aspect, too, and coming from a background of working with Java in Fortune 500 companies, this certainly makes me wary of embracing the new.

But, at the end of the day, it very much falls into how you view the build system philosophically: should the system allow you the greatest amount of flexibility, or should it try to force devs to stay within the guard rails? For me, I've become much more in favor of the latter over the years, and so Maven aligns much more with how I do things. And it is for that reason that I'll definitely not be the decision maker for either this or using Kotlin at the end of the day.

gdude2002 commented 4 years ago

I've spent basically the entire day working on a proof-of-concept Gradle setup, and I feel like I've been quite successful! I would appreciate if anyone interested in this issue would take a look in the changes in the new Gradle branch, and let me know what you think.

A few notes:

There are probably some other things I forgot, feel free to ask any questions you might have. If people are happy with my approach and we feel that the time is right, I will open a PR.

deathcap commented 3 years ago

Hey all, I'm the one that changed from Gradle back to Maven in 2015. It was the first change I made as part of the Glowstone++ fork, a major reason as smartboyathome mentions was Gradle was a lot slower back then, it was cumbersome to wait for the project to rebuild after making changes, while it was pleasantly fast with Maven. Maybe newer versions of Gradle solve this problem with caching and incremental builds etc, but that was the rationale back then.

Another reason was for familiarity. The original Bukkit project used Maven, and both Spigot's and Paper's continuations still use Maven from my understanding, so someone coming from these projects (or possibly from a plugin developed for this ecosystem, though they might use other build systems) will feel right at home when contributing to Glowstone. They will already know Maven and therefore know how to build immediately, lowering the barrier to new prospective developers. Maybe less important now, but I felt it was important to maintain historical continuity from upstream projects at that time.

Looking at Gradle now, it seems to have come a long way but is still somewhat controversial. Some love it, some hate it. This thread on Hacker News today has many different interesting (and often passionate) opinions: https://news.ycombinator.com/item?id=25801986 "The Problem with Gradle"