3 ms·
Maven dependency resolution is not great, mind. For example, if you have a multi-pom project with a parent pom (not unusual in a medium-sized codebase, never m
by barrkel 9y ago
Maven dependency resolution is not great, mind.
For example, if you have a multi-pom project with a parent pom (not unusual in a medium-sized codebase, never mind large), and you have unit tests in your child poms, they'll get executed with dependencies resolved locally for that child pom, and not with the global dependency resolution that satisfies all constraints that need satisfying at the parent level.
The upshot is that you easily end up running tests using different versions of dependencies than what you deploy with, misleading you into thinking things are working, and can end up with hilarious NoSuchMethodError at runtime.
The "solution" is to pin your versions using dependencyManagement, but that's no real solution at all, not least because it's neither automatic (though dependency convergance using Maven Enforcer helps, and I've developed some scripts that help further) nor is there an easy route forward when you want to bump versions safely.
- wellpast 9y agoHaving the choice to pin versions separately per module is a desirable feature, especially for multi-module builds with different deploy artifacts. So this is no problem at all; deciding which versions to pin per artifact/module is the programming job — no tool can automagically decide this for you correctly.
- barrkel 9y agoI'd prefer the choice to specify versions in submodules, with the versions of dependencies chosen and pinned via the global resolution, producing a fixed set of dependencies in a file I can check in, like Gemfile.lock in the Ruby world.
- lmm 9y ago> For example, if you have a multi-pom project with a parent pom (not unusual in a medium-sized codebase, never mind large), and you have unit tests in your child poms, they'll get executed with dependencies resolved locally for that child pom, and not with the global dependency resolution that satisfies all constraints that need satisfying at the parent level. As it should, otherwise you'd get the even more hilarious situation where your tests pass when you run the single-module build but fail when you run the multi-module build. > The "solution" is to pin your versions using dependencyManagement, but that's no real solution at all, not least because it's neither automatic (though dependency convergance using Maven Enforcer helps, and I've developed some scripts that help further) nor is there an easy route forward when you want to bump versions safely. This is not a maven issue, it's a combination of Java's flat classpath and the reality of diamond dependencies on versioned libraries in any system. We could allow multiple versions of a transitive dependency on the classpath but then you get Rust's hilarious "expected Foo but was Foo" type errors. Java 9 modularisation should reduce the problem by allowing modules to have explicitly private dependencies, but the problem exists everywhere.
- barrkel 9y agoThis is not a maven issue, it's a combination of Java's flat classpath and the reality of diamond dependencies on versioned libraries in any system This isn't true; there are better solutions already existing. E.g. Ruby with the Gemfile.lock approach. I'd like to be able to do a two-step: do a global analysis of dependencies and pin the common versions for diamond situations, but not need to maintain or calculate those pinned versions manually. And I still get to use the pinned versions from the global resolution for executing tests etc. on submodules. As it is, I've had to write a bunch of tools to rewrite the dependencyManagement as and when required. The main app I work on is linked into the Hadoop ecosystem, and that dependency set ends up being quite large. Another issue with Maven is rebranding: when the groupId of an artifact changes, but the package and class names don't; see e.g. asm / asm vs org.ow2.asm / asm, or the whole codehaus debacle. I have spent more than two weeks of my life updating, maintaining, fixing, researching and tooling Maven pom files, and it was almost all around deficiencies in dependency management. Let's not get started on trying to get builds to work reliably offline, caching maven repositories, etc.
- lmm 9y ago> This isn't true; there are better solutions already existing. E.g. Ruby with the Gemfile.lock approach. I'd like to be able to do a two-step: do a global analysis of dependencies and pin the common versions for diamond situations, but not need to maintain or calculate those pinned versions manually. And I still get to use the pinned versions from the global resolution for executing tests etc. on submodules. I dislike this for the same reason as before: I find it really valuable that building a single module on its own behaves the exact same way as building that module as part of a multi-module project. If you want to ensure that the tests run against the same version as in the final product, I do that by making eviction an error. > Another issue with Maven is rebranding: when the groupId of an artifact changes, but the package and class names don't; see e.g. asm / asm vs org.ow2.asm / asm, or the whole codehaus debacle. Maven has better handling of this than most; it can at least warn/error when this has happened, and if you're using the shade plugin or similar it will warn or error when two jars contain the same classes. Yes it's a problem, but it's much more of a problem in other ecosystems. > As it is, I've had to write a bunch of tools to rewrite the dependencyManagement as and when required. The main app I work on is linked into the Hadoop ecosystem, and that dependency set ends up being quite large. There are standardized plugins for the common use cases e.g. "mvn versions:use-latest-releases". Most things that can be automated are. But since most of the library ecosystem predates version ranges and semVer, there simply isn't an automated way to know when using a newer version of a transitive dependency is safe or not.