Nicolas Frankel is an IT consultant with 10 years experience in Java / JEE environments. He likes his job so much he writes technical articles on his blog and reviews technical books in his spare time. He also tries to find other geeks like him in universities, as a part-time lecturer. Nicolas is a DZone MVB and is not an employee of DZone and has posted 217 posts at DZone. You can read more from them at their website. View Full User Profile

Maven doesn’t suck, your POM does

10.10.2011
| 9728 views |
  • submit to reddit

Maven bashing is an all-time favorite: there are plenty of articles telling how Maven downloads the whole Internet, or how POMs are bloated and so on.

While I agree that Maven could be perfected, I’m also aware that some (if not most) of its shortcomings are not intrinsic but are caused by (very) bad configuration. Worse, even if used correctly in your projects, problems sometimes come from third-party dependencies! You do not believe me? Well, two examples follow, from standard libraries.

Log4J

Coming from the classic logging framework, this may seem a surprise but log4j POM is a mess. Just look at its dependencies section:

<dependencies>
  <dependency>
    <groupId>javax.mail</groupId>
    <artifactId>mail</artifactId>
    <version>1.4</version>
  </dependency>
  <dependency>
    <groupId>javax.jms</groupId>
    <artifactId>jms</artifactId>
    <version>1.1</version>
  </dependency>
  ...
</dependencies>

Interestingly enough, Log4J depends on the Java Mail and JMS API! If you are using your application in an application server, you may be in for a rude surprise as conflicts may arise between your dependencies and the libraries available on the server.

Moreover, while some users may have the need of mail or JMS appenders, this is not the case for all of us. As such, there’s clearly a lack of appropriate modularization in the design of the library. Luckily, the above POM is an excerpt of version 1.2.15. Version 1.2.16 uses the optional tag for those libraries (which breaks transitivity): it addresses our application server use-case but is still a problem for those needing the dependencies as they have to add the dependency manually. See here for a thought or two on optional dependencies.

If we need version 1.2.15, there are basically two solutions.

  • Clean but cumbersome: we have to manually exclude JMS and Mail from each POM using Log4J. Who said software development was fun?
  • Gruesome but effective: if we have a Maven enterprise repository, we correct the POM (i.e. we add optional tags) on the repository.

Jasper reports

The Log4J example was straightforward: just the side-effects of bad modularization. Jasper’s POM has another twist, just look at a typical dependency:

<dependency>
  <groupId>com.lowagie</groupId>
  <artifactId>itext</artifactId>
  <version>[1.02b,)</version>
  <scope>compile</scope>
</dependency>

The version part means the dependency’s version should be between 1.02b included and the latest version. This obviously has two drawbacks:

  • From an architectural point of view, how can the POM provider guarantee there won’t be an API break with the latest version?
  • From a Maven POV, it means Maven will try to download the latest version. In order to do that, it will try to contact repo1… You’re beginning to see the problem? If you’re behing a corporate proxy that isolates you from the Internet, you’re toast.

The POM excerpt comes from version 2.0.4. Starting from version 2.0.5, Jasper’s designers used only single version dependencies.

If you’re stuck with older versions, the only solution here is to replace the POM with a manually crafted one that do not use unboundedversion dependencies on your enterprise repository.

Conclusion

Despite the constant noise on the Internet, Maven is a wonderful tool. Yet, even if I take the utmost care to design my POM, some external dependencies make my life harder. It would be better to stop losing time complaining about the tool and invest this time helping the developers of those dependencies to provide better POMs.

 

From http://blog.frankel.ch/maven-doesnt-suck-your-pom-does

Published at DZone with permission of Nicolas Frankel, author and DZone MVB.

(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)

Comments

Jilles Van Gurp replied on Mon, 2011/10/10 - 1:29am

Sorry but this is too easy. The reason most people end up with a messy pom is because the underlying system is over engineered, very complex, and poorly documented. All those subtle interactions between different profiles, implicit dependencies, weird and inconsistent plugin configurations, etc. lead to a perpetual state of uncertainty where people fear to touch the pom because they have no way to anticipate the effects of their actions. I've found that if you are not deeply familiar with the maven internals, you stand no chance whatsoever doing anything more than just the basics (i.e. compile and jar stuff) and are likely to get even that wrong at least partially. I maintain a few maven projects and the amount of complexity for what it does is in my view amazing and it causes us loads of problems every time it breaks. It's probably not the best pom file, especially since so many 'experts' tried to fix it by now that most on my team have no clue what 95% of the lines are there for.

Nicolas Frankel replied on Mon, 2011/10/10 - 1:51am in response to: Jilles Van Gurp

Hello Jilles,

"I've found that if you are not deeply familiar with the maven internals, you stand no chance"

I beg to differ but knowing your tools is the first step. I would be very suprprised if Ant (or Gradle, or Buildr, or whatever tool you use) would be different and let you do the world without a fine knowledge of it... Now, your comment is too easy.

Besides, that is not to say Maven is perfect, just that you've to clean in front of your doorstep first. And from what I understand of your environment, I wish you good luck.

Wojciech Kudla replied on Mon, 2011/10/10 - 2:16am

Nicolas, great read. Thanks.
I entirely agree. Maven is a fine dependency management engine, but lack of understanding by people using it causes all sorts of negative comments and feedback.

Fabrizio Giudici replied on Mon, 2011/10/10 - 2:22am

Nicolas, you nailed it. I've had a similar post in my buffer for some time, especially after a discussion at JUG MIlano, a few months ago. In that circumstance, for instance, a fellow found that a lot of the dependencies he was using weren't declaring their license. Of course, no impact on the build so this is a minor problem, still it's a proof of bad POMs around since it takes a few second to fix it and having complete metadata is a plus for users.

Jilles, I don't understand your comment. Maven could have some problems, but I don't understand how internals are related to the POM structure, at least in the simple type of examples we're making. 

Question. Does exist a sort-of-findbugs for Maven? I mean a QA tool which points out bad practices such as those we're talking of. I think it would make a lot of sense.

Mladen Girazovski replied on Mon, 2011/10/10 - 3:35am

I completely agree with Nicolas here, if people don't care to learn the tools they are using, they will fail. btw, log4j 1.2.14 doesn't have those dreaded dependencies.

Jilles, most of your arguments could be applied to ORMs like Hibernate and EclipseLink as well, if people don't understand the tools/frameworks they are using, they will fail and blame the tools/framworks for their lack of understanding.

Personally i love Maven, sure, it has its quirks and can get very complex, but i prefer it everytime over a scripted build that i or another new developer would have to learn from scratch about how they work.

 One of the best things about maven is that configuration can be very centralized (ie. company/parent poms) and one maven expert usually is enough to take care of several maven build projects.

Jonathan Fisher replied on Mon, 2011/10/10 - 11:19am

I very much love Maven, and my entire enterprise relies on Maven... but Maven sucks because build configuration is tied to project inheritance. Not all projects share bloodlines, but project build configuration is a cross-cutting concern. Maybe I want all of my WARs to be built in a certain way. Can't do that in Maven without massive copy/pasting (archetypes), or making all of your projects share a bloodline. Neither is a great solution.

Michael Remijan replied on Mon, 2011/10/10 - 12:40pm

I can checkout from source control 10+ year old projects of mine which use ANT and it only takes as long as it takes for ANT to run for me to build those projects.  Contrast that with 2 year old projects which use Maven...I cringe every time I need to checkout a Maven project to a environment (computer, network, etc)  because it ALWAYS takes hours of fiddling with settings.xml and multiple pom.xml inheritance to get it working.  I'm not making a claim as to which one is better, just telling of my experiences. 

Mikael Grev replied on Mon, 2011/10/10 - 1:32pm

Yeah, it's always a good idea to blame the users. Make the users change, not Maven.

The users are what they are. Adapt or fade away.

Cheers,
Mikael Grev

cowwoc replied on Mon, 2011/10/10 - 1:37pm

I agree 100% with Jilles here. I've been using Maven for a few years now. There underlying system requires a lot of heavy lifting in return for less and less benefit. There are way too many edge cases. The system is obviously over-engineered and poorly documented.

 

The most annoying problem I routinely run into every couple of weeks is that Maven ignores invalid configurations silently (following an xml "best practice"). This means that if you mistakely past code into <configuration> instead of an outer element stuff will silently fail.

 

The ideas behind Maven are great. The specific implementation of those ideas is crap.

Yann Cébron replied on Mon, 2011/10/10 - 1:50pm

A good tool won't even allow you to do stupid things. Unfortunately, Maven failed that test for me in many regards.

Fabrizio Giudici replied on Mon, 2011/10/10 - 3:17pm

 

@Jonathan Fisher  It's perfectly possible to have common behaviours in "cross-cutting" mode. You just create profiles in your superpom - this doesn't mean that all your projects will have a "common blood line" since profiles are not active by default. Profiles should be activatable by looking at the presence of a certain file. In this way I can have all war / android / jetty / aspectj modules working in the same way. More info at http://weblogs.java.net/blog/fabriziogiudici/archive/2011/07/19/maven-pom-composition-means-profiles . In any case, Maven 3.1 will introduce traits.

Given that, it's true that "the users are what they are". Indeed, generally speaking most of the software around is written in a poor way, be it using Maven, Hibernate, or whatever. Probably the whole IT segment should fade away.

Nicolas Frankel replied on Mon, 2011/10/10 - 3:40pm in response to: Fabrizio Giudici

@Jonathan @Fabrizio

I think that Fabrizio' concern is legitimate - I have the same :-)

I also think that Maven 3.1 will address this concern. More later, once I've read through the entire documentation...

And to add to the already boiling blood, we're not users, we're software engineers. While I agree that misplaced configuration should throw an exception (which is admittedly not the case), we cannot afford to be idiots. In fact, most frameworks (Hibernate, Spring, whatever) require a certain frame of mind when using it.

My bad, I forgot there's also a trendy way of thinking that blames everything on frameworks and that propose we develop our own tools. Feels like 10 years ago when each company had to develop its own... Forget that last paragraph, I feel like an old geezer having written that :-)

Jonathan Fisher replied on Mon, 2011/10/10 - 10:10pm in response to: Nicolas Frankel

@Fabrizio @Nicolas

Thanks for the advice, the profile thing is a 'clever' way to solve the problem, I'll give a whirl.

Maven 3.1 is supposed to have "mixins" which was a feature CUT from maven 3.0... Why? I dono, maybe they were to busy removing the awesomely useful "-r" recursive reactor mode. Contrasting this with the points in the article, I think these are legit complaints against Maven. "Downloading the world" is pom-suck problem. Removing useful features (-r) and not separating build configuration from inheritance are fundamental problems with Maven.

Yannick Menager replied on Fri, 2011/10/14 - 5:34am

Well, not going into all the other problems that maven has, the issue is not that the poms are bad, it's that maven dependency management isn't flexible enough to handle that kind of use cases.

Ivy is *much* more powerful in that regards. For example below is my sl4j ivy.xml

When i need to depend on just the sl4j api, i would create a dependency on the "api" config.

<dependency org="org.sl4j" name="sl4j" rev="latest.release" conf="default->api"/>

If I want to also have the jcl dependencies, I would create the dependency on the "jcl" config. That would automatically not just add the sl4j jcl suport jar file, but also it's dependencies (jcl itself)

<dependency org="org.sl4j" name="sl4j" rev="latest.release" conf="default->jcl"/>

I've tried many times to convert to maven, but I always end up going back to ant + ivy because it more reliable and powerful than maven

<?xml version="1.0" encoding="UTF-8"?>
<ivy-module version="2.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
            xsi:noNamespaceSchemaLocation="http://ant.apache.org/ivy/schemas/ivy.xsd">
    <info organisation="org.sl4j" module="sl4j" status="release" revision="1.6.1"/>
    <configurations>
        <conf name="api"/>
        <conf name="simple" extends="api"/>
        <conf name="jcl" extends="api"/>
	<conf name="jdk" extends="api"/>
        <conf name="ext"/>
    </configurations>
    <publications>
        <artifact name="slf4j-api" conf="api"/>
        <artifact name="slf4j-simple" conf="simple"/>
        <artifact name="slf4j-jcl" conf="jcl"/>
        <artifact name="slf4j-ext" conf="ext"/>
	<artifact name="slf4j-jdk14" conf="jdk"/>
    </publications>
    <dependencies>        
        <dependency org="org.apache" name="commons-logging" rev="1.1.1" conf="jcl->api"/>
        <dependency org="ch.qos" name="cal10n" rev="0.7.4" conf="ext->default"/>
    </dependencies>        
</ivy-module>

 

Lund Wolfe replied on Sat, 2011/10/15 - 7:08pm

The intent of Maven was to provide a simple standard/convention for building applications that you could learn once and reuse in new applications and understand in other applications using the same standard with little additional effort. For existing simple or standard applications or new development that can follow the standard, Maven works very well. If you know Maven best practices and you don't go plugin happy, you may be proud of your Maven project.

Of course, a maven project/pom can be done badly, just like an Ant build.xml, and this is pretty common. It's probably more of a problem in Maven because the technology is younger and less mature and there is less skill in using it properly. Developers also often like to over-customize, or over-use their tools, or do weird things to weird things and Maven gives you lots of opportunity to do that.

If your project is older, complex, or nonstandard, then Maven is going to get complex and confusing very fast. You are also dependent on your dependencies' poms being done well or overriding them and pulling their fixed poms or artifacts and dependencies from your own repository.

If your Maven project is unreliable or incomprehensible/unmaintainable, you don't need to apologize for converting it to something else, like Ant. It may make sense to convert Ant to Maven or Maven to Ant. Use whatever tool makes it easier, simpler, and better and move on.

Gagandeep Singh replied on Sun, 2013/02/17 - 3:32am in response to: Mikael Grev

 Totally agree with Mikael . Creating a simple ear is a pain .

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.