Monday, October 27, 2008

Maven Sucks

Tools like Maven make me want to quit the software industry before I die of frustration. I've wasted basically the last two days screwing around with problems related to Maven. In a nutshell, Maven does not provide a consistent or reliable build environment.

Modern software is not written from scratch; it's assembled from myriad components from other vendors, in much the same way that car manufacturers buy their parts (seats, brakes, wiper motors, radios) from other companies. And just like a car seat is itself made of springs and fabric and metal bits that come from yet other manufacturers, each software component may itself be assembled from other components.

Maven is a tool to help manage all the little pieces that fit together into a software product - to manage the fact that my product consists of components X, Y, and Z, which in turn require the presence of P, Q, R, and S, which in turn require A, B, and C; to fetch those components from wherever they come from if they're not already on my computer; and to make sure that the versions of these different components are all compatible.

But it sucks. Maven wants to update things without me asking, so that if I run a test twice in a row I don't necessarily get the same results. Maven wants to download things without me asking, so a task that took 15 seconds the last time might take a few minutes, or fail utterly (if I lose my network connection), leaving me in an unknown and inconsistent state where I can't build at all. And most frustratingly, Maven is itself highly modular, meaning that it's not all downloaded until it's needed, meaning that in the event of network trouble it can again fail utterly. Networks are not yet reliable enough for that to be okay.

Further, Maven seems to do a crappy job of understanding and resolving or reporting version conflicts. I'm extending some test code, that's supposed to exercise version 3.2.5 of product HappyWidget. The test code therefore tells Maven that it needs HappyWidget version 3.2.5. But the test code also needs OtherThing version 2.7.1; which needs FussyBit 2.0.1; which needs HappyWidget 3.1.2. Whoops! This is a version conflict. It would have been easy to fix, except that Maven didn't tell me there was a problem, it just silently deployed HappyWidget 3.1.2. So all along this test was actually testing HappyWidget 3.1.2. What's really scary is that when I uninstalled and then reinstalled everything, without explicitly making any changes in my dependencies, the behavior changed - now it's deploying 3.2.5, which is nice for my test but not so nice for the corresponding code that is supposed to test HappyWidget 3.1.2.

The first requirement of a build tool is that it should behave predictably. Maven fails.

It's late and I'm not going to spend more time saying all the hateful things that Maven has done to me in the last two days. I will blog in the future about what I think the solution to this should be.

4 comments:

Unknown said...

I agree with you and I'm surprised nobody else seems to have noticed. Maven makes hard what should be the most important feature of a build system: reproducibility.

We've had builds fail over night because some unknown entity on some internet server out of our control decided to upgrade a plugin at that time. Sure, you're supposed to specify explicit versions of the plugins you use. But these plugins may use other plugins and those dependency specs are normally out of the control of the end user.

We've had trouble piecing back together a build at all when we resurrected a project after a year and a particular dependency was just no longer to be found in the usual repositories.

When doing a build on my local machine, I'm never sure what I'll get. Depending on the time of day Maven may decide to update the snapshots from the department repository. Unless I examine the log, I'll never know whether I'm now working with different software than before the build.

Over the past 3 years of working with Maven I've come to believe the following things:

- Building and updating should be separate operations at the discretion of the developer. I never want one to implicitly cause the other.

- Anything a build depends on belongs in a version control system. This includes your own build sources as well as 3rd-party dependencies. This seems to me is the only way you can guarantee reproducibility into the past. A Maven repository is nothing more than either a cache or an Internet resource. Neither is what I want my build to depend on.

- Versioning should be handled by a version control system rather than by encoding a version number into file names. Any version number in file names or file contents - such as in POM files - obstruct basic versioning operations such as branching and merging.

- Version numbers in file names lie. I saw this post today which explains how. This goes back to the last point.

- When the configuration of your build tool is so complex that you need write a program (Maven Release Plugin) to update it consistently just so you can then release your software, your build tool uses the wrong configuration abstractions.


That said, Maven brought some good things to the table such as an attempt at transitive dependency management. I say attempt, because of the conflict resolution weakness you mention and because the conflict problem isn't truly solvable as long as there is a single, linear Java classpath. JSR-277 I believe will address the issue the right way.

In terms of alternatives to Maven I haven't really found what I'm looking for: a build system that has some kind of transitive dependency model, but does not attempt to be a pseudo versioning, download or repository system.

I'm interested to hear your thoughts.

Walter Harley said...

Albert, I agree with everything except "nobody else seems to have noticed." I titled the blog entry "Maven Sucks" because that's a popular title for blog entries :-)

Here's another peeve: with Maven, it's impossible to do even incremental development tasks without network connectivity. I don't fly a lot, but when I do, I like to get some work done. Can't develop on a plane with Maven, though, because touching any part of the dev process (e.g., trying to run a test that you haven't yet run) might provoke a download. There is simply no way to know whether or not you have everything you need, in advance of needing it.

We are used to certain things being reliable, at least in the developed world: for instance, I've never had the electricity in my hotel room be flaky. The internet is not there yet. The internet is often not available. Network-enabled tools need to be smart enough to deal with network failure. Maven is not.

Unknown said...

'I agree with everything except "nobody else seems to have noticed."'

You're right. I wasn't using bad enough language for my search terms. I didn't notice everybody else had noticed.

So I guess everything that needed to be said about Maven has been said.

Which leaves us with what? With Quokka , Gradle?

KingStreetMike said...

yes indeed it sucks - wtf half the time I dont know what its doing. I simply want to run a plugin - but what phase does it belong to ? I've read all the literature about the different phases - but why would a plugin run once but not immediately again.

It messes with the web.xml puts it in a bunch weird locations.

Now, when we install the M2E plugin - or if u want to use Spring Tool Suite - then some of the lifecycles are not mapping to the ones in the maven file.

Basically - I hate Maven. What I prefer is just letting Eclipse do its job. Eclipse is an awesome tool - but when u add Maven into the mix it really messes things up. I'd rather just let eclipse do the build process. Maven can go suck a big fat d*ck.

Dont get me started on Captcha