I wonder what people use/need apart from the usual stuff in Maven nowadays.
In the last 5 years, I didn't need anything more than:
- resource plugin
- compiler plugin
- jar plugin (jars, test jars, javadoc jars)
- surefire/failsafe
- shade plugin for repackaging to avoid classpath hell
- assemble plugin
- license plugin
Most of the issues I had were with the shade/assemble/license plugins.
I consider myself a Maven power-user and like the tool compared to others (Gradle is too ant-like, resulting in non-standard builds, sbt is just a torture tool).
With time, I concluded that the simpler it is, the better.
I've been around for a while, I've used many different build systems for JVM based builds (Java, Hybrid Java/Clojure, Scala) and Maven is by far the simplest most solid.
The basic reason is it's commitment to being declarative.
I understand why programmers want imperative (we're programmers) but it's just the wrong choice for a build system.
I've worked on many OSS projects. I've never pulled a Maven-based project that didn't immediately build and immediately load into my IDE. However for imperative based build systems (Gradle, Ant, now Mill) it's almost inevitable that you won't be able to get the build to work right away or pulled into your IDE in a sensible way (as IDEs cannot read imperative statemetns).
I've created many many build with Maven with many many different demands (polygot codebase, weird deployment artifacts, weird testing runtime needs, etc etc) and Maven has never let me down. Yes, in some cases I've had to write my own plugin but it was good that I had to do that; it forced me to ensure I really needed to -- the Maven plugin ecosystem is already great and covers 90+% of use cases of builds.
I've met a lot of Maven naysayers and the disdain is almost always either some weird aversion to XML (such a trivial reason to choose a worser build system) and/or because the programmer never took the time to understand the rather simple Maven runtime semantics and architecture.
> imperative based build systems (Gradle, Ant, now Mill)
Build code in Mill is pretty declarative. You're using the word to mean "not 'pure, serialized data'".
> IDEs cannot read imperative statemetns
They can, however, run the code to dump the structure.
It's easy for code to embed pure data; on the flip side it's hard to encode behaviour in serialized data. More often than custom Maven plugins I see people just drop down to using shell.
Author here. The neat thing is, with Mill you don't need any of those plugins because it's all built in (except for the license plugin I believe), and is tested/documented together in the main codebase. So it generally all works pretty well together and you shouldn't have issues.
Mill generally is able to replace a lot of first-party/third-party extensions with builtin functionality: beyond the plugins above, it also subsumes autoformatting plugins, linting plugins, external tools like sdkman/jenv, and so on. Thus when using Mill you often don't even think about "what plugins I need", because the bulk of common use cases are provided out of the box, and you can instead focus on your actual project and application code
Ya know, I've directed a lot of criticism at Maven over the years... and most of it well-founded, I believe, even in hindsight. And yet, today, I find that of all the Java build tools, Maven is my preferred one. Part of that is me, normalizing the pain of Maven in some regards, and part of that is places where they have improved the tool. But however you break it down, it is indeed the case that for the most part Maven "just works"™. That is, at least for Java. I don't do a lot of Scala or Kotlin or anything, so no comment there. And for Groovy, I'm usually doing Grails projects which default to Gradle, so I tend to use Gradle in that context. But for plain Java projects, I honestly find Maven to be the path of least resistance.
Kinda fascinated by this opinion, I was never a fan of either ant or maven, but I find Gradle perfectly fine for Kotlin, maybe there is either a little difference between Java/Kotlin, or I was mostly spending my time with "old" maven setups, or something completely different. I'm not saying ant and maven have a lot in common, just that I didn't like either.
I've had the misfortune of having Maven forced on me for Scala projects, I just can't agree with you. The overhead of starting the compiler so often is a killer, and makes your builds much slower. Unless there's been some improvement of Zinc/Bloop/Etc with Maven since I've used it.
I think I would prefer to use Mill than Maven (I haven't used Mill myself) ... going through the video tutorial, it's clear that it's also a very simple system without some of the ancient baggage of Maven (xml, too many plugins, etc).
I don't think "Scala+Maven is worse than Scala+sbt" is opposite to "Scala+sbt is worse than Java+Maven".
As much as I like to hate Scala, in my past experience if you have sbt console open, then hit compile after every few changes the feedback loop is tight-ish - barring crazy Scala features being used.
Sorry for the ambiguity. I have also had to write Scala in application code for those projects, but that's because the framework we used, Play, is written in Scala and it's Scala core leaks in many places where the Java compiler can't figure out the kludge of byte code generated by scalac.
I actually rather enjoy Scala as a language when I don't have to interact with it from Java and when I don't have to go full into the FP ZIO/Cats world.
My main problem with Maven is that it's dog slow and incremental compilation doesn't really work, especially on CI. For huge repos that's a real issue.
In a sense I feel that part of the microservice craze is due to the fact that many of our build systems are not good enough to allow us to work with huge monoliths efficiently. Gradle is a bit better (definitely faster), but comes with additional complexity. Haven't tried Mill.
Author here. Mill definitely works pretty well for monorepos. Within a single module Mill incrementally compiles the Java files, between modules Mill caches and parallelizes things much more aggressively, and when running tests Mill can take your PR's `git diff` and selectively execute only tests downstream of your changes.
This all comes built-in without any plugins or anything, and serves to help speed up dev and CI workflows even on pretty large codebases.
Does Mill have the capability to enforce dependency constraints on transitive versions without declaring them explicitly? I find this to be quite a useful feature for dealing with automated security review and gradle can do that:
If you are doing Kotlin and especially Kotlin multi platform, Gradle with the kotlin dialect (not Groovy) is the default choice in the ecosystem. That might change soon as Jetbrains has been working on their own build tool (amper). Maven is an afterthought in the Kotlin world. You can obviously use it with things like Spring. But it's not a well supported, or well documented thing in many Kotlin projects, the Kotlin documentation, or any of the Kotlin build tooling that Jetbrains supports.
Just look at all your Kotlin library dependencies on Github and do a little surveil of what those use. There's a clear picture that emerges of what is common and what is a distinct outlier. Maven is clearly not a mainstream choice in many Kotlin projects on Github. There are a few maven projects. But mostly it's all gradle. And most of that is using the kotlin DSL dialect of that at this point.
Unlike Maven, Gradle has seen a lot of active development adding many similar features that are being advertised for Mill. For example the configuration cache is now default in the upcoming major version (9.0 release candidates are out). And it does make a big difference if you use that. Although cache coherence issues are obviously a potential problem here.
I don't know Mill and it flew a bit under the radar for me. So I won't say anything negative about it. But, I'm not that optimistic I can use it on my multi platform kotlin projects. That's just because a lot of Kotlin is developed in lockstep with the compiler and gradle plugins that it uses, which are very gradle centric. For example, Kotlin multiplatform builds with its own gradle plugin that ships with each Kotlin release. And replacing that with something else is not really that trivial on the type of projects I do.
A lot of Kotlin multi platform needs quite complicated build steps to interact with build tooling for different platforms (llvm, xcode, wasm, jvm, node, etc.). Most of that stuff is being developed by Jetbrains. They don't spend a lot of time on thinking about or supporting maven.
I'm not a Gradle fan boy BTW. I've used Maven and Ant before that. I really dislike the Groovy legacy in Gradle. It makes everything so complicated and convoluted. And that leaks through in the Kotlin DSL for gradle. And clearly Jetbrains is also not that happy with gradle because they are working on Amper.
But it works and the performance work they've been doing in the Kotlin build tools and Gradle is really paying off. I've seen quite massive build speed improvements over the last few years for the same projects on the same hardware.
In the last 5 years, I didn't need anything more than:
- resource plugin - compiler plugin - jar plugin (jars, test jars, javadoc jars) - surefire/failsafe - shade plugin for repackaging to avoid classpath hell - assemble plugin - license plugin
Most of the issues I had were with the shade/assemble/license plugins.
I consider myself a Maven power-user and like the tool compared to others (Gradle is too ant-like, resulting in non-standard builds, sbt is just a torture tool).
With time, I concluded that the simpler it is, the better.