Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

This might be more appealing to programmers outside the Java ecosystem if it didn't depend on Gradle.


Gradle and Maven are both a million times better than whatever constantly changing collection of random stuff you have to use to build a contemporary node project.


Nah. Gradle has its advantages but it's way more complex than building a node project. The Gradle DSL is utterly incomprehensible to anyone that isn't a seasoned Java dev. Honestly, I struggle to think of a language with a more complex build system than Gradle, besides building cpp apps.


Seasoned Java/Kotlin dev:

Nah, Gradle is a fucking mess no matter what. If you don't absolutely understand the gradle life cycle, how to avoid task configuration, keeping everything lazy, avoid cross configuration, understand that buildSrc is shit, gradle will be hell.


Agreed. Maven is boring, but for most stuff it just works. Hard to customize, but before doing that, ask yourself why you're doing something different than millions of other projects. Go with the defaults and things will work.

Gradle feels to me like trying to set up a webpack project. Loads of magic configuration no one dares to touch after it happens to somewhat work correctly.


I dunno, I understand building cpp apps much better than building a Java one. And I have basically zero experience with both.


SBT is in another tier of incomprehensible stupidity


Nothing is a bigger time killer than sbt and scalac!


I’m not a big fan of kotlin, but gradle does have a kotlin dsl as well which is in my opinion much more readable and explicit.


you can write gradle in kotlin script, the same language as your code if it's kotlin.


Let's not compare Maven to Gradle. One is a stable, rock-solid, decades old declarative build tool with reasonable performance and excellent backward compatibility - the other is a configuration, semantic and maintenance nightmare.


Gradle is a very very good build tool from an engineering perspective - it can seriously speed up compilation, is actually correct (maven sometimes need a clean install to be 100% sure it creates the actual things) and basically has every capability out there.

But I do agree that the dsl is quite cryptic.


Gradle has actually saved my build. About 3x faster than my old Maven setup. Also, my build files are much less bloated.

The only problem I find is the API updates between major versions. Still, I’m never going back to Maven. Love Gradle.

Building embedded server apps, many sub projects, single Java/Kotlin codebase.


The only reason Gradle is faster is because it uses a daemon for build caching and leverage JVM code optimization.

Once you apply that same strategy to Maven, it actually tends to beat Gradle in performance too. See Maven Daemon: https://github.com/apache/maven-mvnd


And if you build from inside IntelliJ, I think it already does essentially the same thing (unless you tell it not to) by importing the Maven project into its internal build system and using a compiler daemon: https://www.jetbrains.com/help/idea/delegate-build-and-run-a...


Gradle also has the ability to skip things it has already done. It won't recompile code that hasn't changed, won't run tests that haven't changed, etc


> actually tends to beat Gradle in performance too.

Mvnd seems somewhat recent compared to Gradle’s daemon feature. Are there any measurements that confirm this statement? I don’t find any in the repo?


You don't need anything to build a node.js app. If you use typescript then yes you'll want typescript, but honestly the experience out of the box in node is pretty fantastic that you don't need anything else, as far as build goes.

Granted if you are talking frontend browser code then sure webpack, but that tool has been around and stable for many years now.

Added bonus too is browser adoption is way better than ever so you don't really need a transpile either, typescript being the exception.


Deno is making Node seem like exactly what it is. Node being mediocre and something a person made over a decade before Deno.


Not sure I agree. NPM as a technology is actually pretty decent and fast. The biggest issue is that package.json doesn't allow comments. Webpack is shit. But there are good alternatives to it now - primarily esbuild.

I'd take that build system over Java's dog slow build systems any day. Just a shame about the JS ecosystem itself. Too many badly written libraries not written in Typescript (inexcusable these days) with a gazillion dependencies.


There's a lot of garbage TypeScript libraries too. I think a lot of this just comes down to size. Smaller languages tend to focus together on maintaining and contributing just one package that does the thing. TypeScript and JavaScript as lowest common denominator languages for many scenarios means there's a lot more options for better and worse. What hurts both as well is they are multi-paradigm while the broader communities are general pushing very hard into a single paradigm which necessitates more libraries and ecosystems.

Loving FP and admiring `fp-ts`'s work, I can't help but think our communities would be better off doing FP in FP languages instead of writing unergonomic and idiomatic code to much of the splintered TypeScript community. Yet, we'll writing things this way because it feels like the correct way to do software, meanwhile a bootcamper would find it incomprehensible; this same person would find an FP language more approachable because there's only one way to code it.


How is Java’s build tool slow? The single frontend compile step is literally the slowest in a badly architected project we use, even though it goddamn deploys to wildfly!

Java literally compiles as fast as it gets, while npm chews through the same files multiple passes, and goddamn barely does anything yet takes eons of time.


Yeah, I have no idea what that person is talking about. I'm in the same situation as you; we can compile hundreds of thousands of lines of Java code in dozens of different jars in less time than it takes for one of our frontend javascript builds to run.


Well, don't start from node then. I like how Go does things, but I don't know if it makes sense for web development. Is Deno good?


The problem isn’t necessarily the quality of gradle or maven but rather that you get one more build dependency, thus increasing complexity of the project.


Maven yes, Gradle is just Ant in disguise.


Honestly I just wish it had stopped at gant [1]. That was truly Ant in disguise and it was glorious.

[1] https://github.com/Gant/Gant


Yup, gradle is a huge barrier to entry - esp. with the whole disparity between kotlin dsl and gradle dsl.

At its core, gradle as a task runner is pretty neat. But the layers of abstraction built upon it often make things superhard when you need to deviate from the setup offered by the starters.

While the official docs have started to show examples in both, almost always a stackoverflow answer or online blog post you find while googling is in the other dsl and converting between them is non-trivial.


All examples in the official docs (bar a few things like custom plugin development) are in Kotlin now. Also the support for the Kotlin build scripts in IDEA itself is a ton better now, it used to break all the time and desync etc but no more.

Gradle certainly isn't great but it's crappiness is overblown especially when comparing it to stuff like npm + webpack.


You can build Kotlin (including Kotlin.js) with Bazel: https://github.com/bazelbuild/rules_kotlin


Kotlin/JS actually does work with Maven [1] – it's just all the MPP and Kotlin/Native stuff that is heavily Gradle-focused. I hope they eventually get to updating the Maven plugins once the multiplatform features stabilize.

[1] https://kotlinlang.org/docs/maven.html#attributes-specific-t...


Technically it might work but you are fighting an uphill battle in terms of documentation, stuff that's just not supported at all, bugs, etc. With Kotlin-js especially, I would strongly recommend to not bother with maven. It's a bit cutting edge and you'll have an easier time doing what everybody else is doing.

If you go the gradle route, of course use the Kotlin Script variety. Gradle is a bit complex and having your build logic written in Kotlin seems like it is the right thing to do.


> having your build logic written in Kotlin seems like it is the right thing to do

Yes, in the abstract it does, but the but way Gradle actually does that (evaluating different parts of the program in different special and magical ways) is extremely confusing. And I don't understand how it could possible require the vast amounts of memory it does.

Maven is horrifically verbose, but at least its model makes sense after learning a few key concepts and the IDE can help you work with that model without setting fire to the CPU.


IMHO maven is not something that is actively supported by many people using Kotlin. If it works at all, good for you. Otherwise, you are on your own. I'd advice against using that with Kotlin.

I have plenty of experience with maven and with ant before that. No project I've touched in the last six years used either of those other than a few conservative and, frankly, clueless/hopeless customers that I've helped out in some of my freelancing projects.

I don't get pedantic about persuading customers that maven is dead as a door nail but there is a pattern of behavior of mostly elderly (i.e. my age) slightly out of their depth CTOs insisting that maven is the way to do things because that's all they know.

I'm experienced enough to not fix what ain't broken. A build system either works or it doesn't. And it's not worth my hourly rate arguing against it. Anyway, it's not that hard to get them working regardless of what you use. I'm old enough to remember DOS batch files being an acceptable solution. Actually wasn't that hard to do either. I love bash shell scripts for the same reason.

People get hung up on build systems performing magic that they don't understand. Maven is mostly just a really convoluted way to compile Java code which isn't even all that hard when you understand what it does. Having done that with batch files I both appreciate what maven. gradle, etc. do and recognize that it doesn't matter much at all. Gradle does most of the same things as maven with less fuss. I'm still well capable doing the same with just bash and a compiler. But it's not worth my time. These days, I spend more time on figuring out github actions than on gradle. The stuff that gradle does is only a tiny part of the business of doing CI/CD these days. Gradle is the easy part.


Yeah. I’ve tried to get into Kotlin multiple times and the tools used for building like Gradle are inscrutable to me.


This is a feature, Gradle is decades ahead of node build tooling.


I like how, last I checked anyway, there was no way to say "install this package" with Gradle; I had to go get the URL first. There might have been a way to do it after first manually adding a repository (maven central or whatever), but I couldn't figure it out quickly.

And then to upgrade to the latest I had to manually go figure out what the latest was, and manually change the line number to the latest version. I did see there's a separate plugin you can install to now add it though, built by a third party, but still.

Decades.


I don't understand your first bit, "install this package" isn't a thing in the java world. There are just dependencies, you don't "install" them.

But this:

> And then to upgrade to the latest I had to manually go figure out what the latest was

Yeah, in the java world you write code against specific known dependency versions. That's why when you try to build it again in a couple months, it still works. I sure wish the JS community would learn this old trick.


NPM has had package locking since what feels like a million releases.

I wish the Java community (which I'm actually also a part of) would stop rejecting everything that's not "the Java/enterprise way" and be humbled by exploring better alternatives, or alternatives with different tradeoffs for once.


I think his point was more of a cultural difference. My IDE actually lints non pinned dependencies as a potential source of errors, whereas in the JS world it seems very common to not pin.


npm uses locks per default, and to disable that, you need to create a file called .npmrc at the root of the project and add package-lock=false to it. I don't think any popular project does that.

It's also a common practice to use npm ci in all build scripts to never update packages even if they declared a version range in package.json, and package.lock not being able to satisfy package.json won't cause lock to get overwritten.


The fact that npm ci does what npm i should do (well, except for starting from scratch each time [0]), says it all. npm is a joke.

[0] Yes, that's right. npm doesn't allow to to install incrementally respecting the lockfile. You can install incrementally with npm i and roll the dice, or install from scratch with npm ci to respect the lockfile. Basically the npm authors took the rm -rf node_modules/ workaround and productized it.


If you have a package.json and you run npm i it generates a package-lock.json from it.

If you run npm i against that package.json and package-lock.json, the latter will never be updated, even if the package.json would be happy with newer versions.

If you manually edit your package.json to have different ranges and run npm i and those ranges aren't compatible with your package-lock.json then the latter will be updated with version that are compatible with your package.json. Further runs of npm i will be as with 2 above.

But of course you may think this behavior is a joke, I do not.


How can I incrementally install exactly what’s in the lockfile, raising an error if it’s incompatible with package.json? This is what I expect npm i to do, but as far as I can tell, npm simply doesn’t support.


> raising an error if it’s incompatible with package.json

How? Why? What's your use-case?


Two essential use cases:

1) For local development, I’m seeking a command I can use after pulling, to safely and quickly install any needed dependencies that have been added by others. Currently I use npm ci but it’s absurdly overkill (and therefore very slow).

2) For CI itself. I cache node_modules/ across builds, which significantly speeds up my builds. Currently I npm i, and check if lockfile changed, and if it did, checkout lockfile and npm ci.

I shouldn’t need to npm ci ever unless my node_modules/ became corrupt for some reason. Because npm ci ALWAYS blows away node_modules/, it’s not a reasonable piece of everyday functionality, it’s just a semantically ambiguous way to rm -rf node_modules/ && npm i -—respect-lockfile (made up flag I wish existed). The obvious explanation is that the npm developers couldn’t figure out how to reliably reconcile node_modules/ with the lockfile, so just gave up and shipped npm ci.

Or if the rm -rf node_modules/ isn’t strictly necessary for npm ci, then give me npm ci —-skip-drop-node-modules, that would be equivalent and fine for my purposes.


if npm i is overwriting the lock file, it means someone updated the package.json, and didn't update the lock file (as in, did not install the update).

btw ci is super fast (caching) unless you have one of those modules that download the whole effing chromium after install (brain dead behavior).


I wish it were so simple. Maybe I’ve just been bit by too many bugs in npm over time, but I repeatedly see npm i change the lockfile when incrementally installing a new package that was correctly locked. Fortunately at least npm ci has always been reliable.

What do you mean ci is super fast? Is it intended to be caching the packages somewhere other than node_modules?


> I repeatedly see npm i change the lockfile when incrementally installing a new package that was correctly locked

There's been some bugs in the implementation but never had anything in the last few years, other than some people accidentally committing unapplied package.json changes, and built a precommit hook and a server-side check for that in many projects.

> What do you mean ci is super fast? Is it intended to be caching the packages somewhere other than node_modules?

Yes: https://docs.npmjs.com/cli/v6/commands/npm-cache#configurati... . If you want a more Java-like (to be more accurate, artifactory-like) experience, you can also opt-in for Verdaccio: https://verdaccio.org/ You can also use the artifactory itself: https://www.jfrog.com/confluence/display/RTF/Npm+Registry

I had more success with verdaccio though.

Quality of the packages has been discussed to death, say about that anything you like, but npm has been rock-solid for me in the last few years. Definitely not a joke IMHO.



I wasn't arguing that gradle didn't have such a mechanism but thanks :)


> Yeah, in the java world you write code against specific known dependency versions. That's why when you try to build it again in a couple months, it still works. I sure wish the JS community would learn this old trick.

I've been writing JS with npm locked to specific, exact versions of dependencies since 2014, IIRC.

Not everyone does this, obviously, but the tooling has been able to at least do a decent approximation of this for a long time (and I was and am very far from being a bleeding-edge adopter).


Okay - "Download and make this package available to my code", if that makes you feel better. "npm install (dependency name)" will 'download and make this package available to my code' from the NPM repository, for the current node project you're in. I can also specify custom repos to use, rather than NPM, if so desired. Gradle's default is "nah, go find the fully qualified URL package name and version number for me and paste it in the gradle build file for me, in the right location".

Once you do that in Node, the package lock will specify what version you've downloaded, to make it a repeatable build. You can tweak it to indicate you want to pin the version at a given levels, as well; that's done in one place, and separately from the package-lock file that gets generated, that tells you what -actually- is being used.

My follow up point is that when that version eventually goes stale, it's as simple as 'npm outdated' to determine if there's something more recent, and 'npm update' to update everything (based on whether you've pinned to a major/minor in your dependency list). You can also update specific packages with 'npm update (package name)'. I sure wish the Java community would learn this obvious 'trick' that every OS package manager enables. I know I want Jackson, say, I should be able to say "gradle install jackson" or whatever, and it would tell me all the options in the repo with jackson in the name. Then 'gradle install jackson com.fasterxml.jackson.core' and it would add that to my gradle file, with the most recent stable version. And 'gradle update jackson' would seek to update that dependency to the latest stable (with some syntax to pin the release, major, and maybe the full version, to enable 'gradle update' to update everything within a particularly defined scope).


To add, gradle also has dependency check as a feature which will show possibly out of date packages.


> There are just dependencies, you don't "install" them

Pray tell me where the dependency comes from then? When I add a ‘This package requires dependency x at version y’ to my gradle/maven file, it doesn’t magically appear on my system.

Or rather, I think it does magically appear on my system, which is incredibly confusing.


The dependency comes from the list of repositories you provide. Even in nodejs you don't manually enter the full URL to an NPM package. You just yarn add node-ipc==10.1 and your tooling will figure it out on its own.

If you enable the general maven repository (the maven() you see at the top of many gradle build scripts), you'll get the code from maven. If you also add your personal repositories (which most people probably don't have), you'll get packages from there as well. I'm not sure how you add a second repository to node package managers, but I assume it's possible in some way without specifying the http download url.

The biggest difference between the two ways of package management in my opinion is that node packages are just a word or two and Java packages are a full com.example.product.service.package name. That's a lot better in my opinion as it distinguishes between projects much more easily. I thought node-ipc was related to the nodejs project, for example. Some nodejs packages use namespaces, but most don't.

Another difference is that nodejs has tons of tiny packages (I'll never get over how silly it is that is-odd and is-even appeared in my node folder by transitive dependencies) whereas the Java world generally uses huge packages almost exclusively. This leads to more boilerplate code (actually having to write simple functions like that yourself), but also to less dependencies that can break.


It downloads it into cache for the first time and uses it at compile time at every subsequent build? How is it magical?

Should it display ads instead and put random executables to my path? Or create a 1000000 file directory everywhere on which windows god damn chokes to open?


This honestly sounds like you not knowing the tool, rather then the tool not having the capabilities.


Could be! Given that I've been across multiple Java shops, including with people who have been in the Java ecosystem for decades now, and I've never had anyone point out how to do this, and in fact seen those self-same people work around these perceived limitations, I doubt it. But it's quite possible the functionality is there, just so buried no one knows about it. Certainly, I haven't seen a response, yours included, that explains how to do it.


Alright, I'll bite. With dependency management being 1) and the update flow being 2).

1.1) Gradle is a build system. As such it doesn't care where you are getting your dependencies. You can skip all public package repositories and only use your own private one or mix and match. Adding repositories is literally as easy as doing the following to your build.gradle file:

buildscript { repositories { google() mavenCentral() maven("your private repo url") }

1.2) As has been mentioned in previous comments, you add dependencies to the project rather than install them in the system. Gradle then has various cache folders where these dependencies recide and will fetch those that it doesn't find locally (new libraries, new versions etc). This is akin to how most software defines its dependencies. Python's pip & requirements.txt, Flutter's pupspec.yaml etc.

1.3) Complaining about having to use a full resource identifier ('com.google.guava:guava:31.1-jre') for the dependency rather than just an alias ('guava:31.1-jre') for the package name simply sounds like complaining for the sake of it. What if a fork exists of guava ('my.forks:guava:31.1-jre'), how would that get used along side the original if dependencies are only defined by their project name?

2.1) In my books, package updating should be methodical processes where each and every update is made in isolation, thoroughly tested and then merged in. In that respect I find it very nice that the build system isn't constantly telling me about a new library version everytime it runs, as it pushes naive developers to upping all libraries to their latest versions immediatly and then scratch their heads when unexpected behaviour starts popping up all over the place.

2.2) Various IDE's have mechanisms for notifying visually about when a package has a new version available to them. There are also various tools available to check for package version statuses, such as the 'Gradle Version Plugin' just to name one. I use this plugin extensively to get information on stable dependency updates.

2.3) If you want to always use the latest version of a dependency, you have various mechanisms available to you. It is easy to declare if you want to always go for the latest major, minor og patch versions automatically. See 'https://docs.gradle.org/current/userguide/single_versions.ht...' for details. I'd hate to work an a project that had not clear version definition though as that would just signal very naive developers and/or sloppy practices (automatically going for latest patch versions is fine in my books).


Even on the Java ecosystem, Gradle is only appealing for those that never had to fix Ant builds.


I've found Gradle to be very straightforward, intuitive, and easy to use. I switched one of my projects from Maven over to Gradle, and coming from Maven XML, the Grade configuration language/DSL was amazing and a breath of fresh air.


I’m going to have to really disagree. While XML might be verbose, it’s dead simple and maven is extremely well documented. Gradle on the other hand is cryptic, relies on stack overflow to document it, and breaks your build scripts every release.


Maven to Gradle is a huge improvement, but I think a lot of people here are coming from the JS world. Package.json is incredibly simple compared to Gradle.


Disagree, maven to gradle is a downgrade. Yes, xml is boring, but it's still incredible simple, almost just a verbose package.json. And it's convention over configuration, if you do stuff like everyone else, it just works.

Gradle however, is a dsl in a language almost no java devs use. All gradle files are different, so copying an example from somewhere else probably won't work in your context etc.


> Gradle however, is a dsl in a language almost no java devs use

Gradle with Groovy sometimes gets kinda hard to comprehend

Gradle with Kotlin is entirely different experience, largely due to proper typing.


Is it? Where does my special css file go, what option is valid in this context, do I need babel, or this other 1000 package? It does tell you something that literally every framework will generate you a file, while you can easily write your build script by hand for even large java projects.




Consider applying for YC's Winter 2026 batch! Applications are open till Nov 10

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

Search: