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

"These abstractions apply to tools and frameworks as well, particularly tools that must scale in their power and sophistication along with projects, like build tools. By hard-won lesson, composable build tools scale (in time, complexity, and usefulness) better than contextual ones."

And then the person that wrote them leaves and we're fucked. If maven doesn't do what you need to do, then chances are you don't need to do it. You may think you need to do it, you probably don't. Maybe what you need is a more powerful deployment system, or something that takes over after your java/scala/whatever is built.

If you're building perl, C, C++, sure, maven isn't going to do it for you. If you're building java, you're sorted.

My favorite is when this sequence happens (I have seen it first hand):

  1. Maven is this external system that we have no control over.
  2. We will write our own system that will be awesome.
  3. Wow, look, every project uses our Build System!
  4. Oh, look, someone on project X changed B.S. and now Projects A-N don't work!
  5. We will lock down B.S. so only the one person who wrote it can change it!
  6. ...
  7. B.S. is this internal system that we have no control over!
  8. ...
  9. Can we add support for merging war files?
  10. No that'll take weeks, and Bob isn't available anyway.
I'm sure you can fuck that up just as well using Ruby. Go for it.

I work in a java shop currently. There's got to be a hundred of us. Every single one uses an IDE.

When I use maven, my IDE just works. eclipse, intellij, netbeans all support maven. Want to put a bunch of files in a common war to share? maven has a merge-war plugin and intellij and eclipse know what it means: they both build projects that copy the files just like maven would do. Better yet, as you edit those files, no matter where they are, both eclipse and intellij update the files in the deploy target and they are available when you refresh your browser. There is a huge amount of investment in making this stuff work. This is convention over configuration.

No tool can do this with Ant (or Ruby) unless it runs the Ant and the Ruby, and then you've side stepped the IDE and reduced them to dumb text editors. With an Ant project, the IDE can't know that when I edit file A, it is transmogrified into file Z. (If it could, it could solve the halting problem). With Maven, the IDE implements convention, and so it know that File A is compiled to File B and then must be copied to location Z because its part of a merged war. Add JRebel to the equation and pretty much any change to the code is immediately runnable. Its dangerously easy to spike away instead of writing tests!



If what you need to do can be done in Maven you don't need to do anything very difficult. Ant scales poorly; dependencies are a particular headache. Maven scales astoundingly poorly.

Here's a very short list of things that are massively obnoxious to do with Maven, but are perfectly reasonable:

- submitting code to a code review site like Gerrit.

- generating code (for example, a parsed SNMP MIB that you want as a Java class so you can refer to it easily).

- integration with a tool like Sonar (yes, there's a Maven plugin. You ever used it?).

- code coverage analysis (yes, there's a Maven plugin. You ever used it?).

- FindBugs style analysis (yes, there's a Maven plugin. You ever used it?).

- interesting dependencies on external libraries (to pick an example from Ruby, the json gem was horribly broken at 1.4.2 and generations of projects have varying requirements for json < 1.4.2, json > 1.4.2, and many other worse things.

- C code (through JNI or anything else, a perfectly reasonable thing to want to do).

- deployment.

From bitter personal experience it is possible to get so wrapped up in this that you think you have achieved something amazing when you finally finish, when it could have been done in a few hours in make or rake.

"Oh, but you can integrate it with your IDE!" The only thing your IDE actually needs to get from the Maven POM is to understand where your source code is, what you depend on and where it is, and how to run your tests. Everything else they do with command line calls, just like it was Ant.


Pretty much everything you mention simplifies to "choose a phase, then add an exec plugin declaration".

Have you looked at http://maven.apache.org/guides/introduction/introduction-to-...?

Maven is particularly good at generating code for later compilation and processing. Your custom code generator just needs to put code into src/generated and it will be picked up.

Given that Maven is used to organize and build some pretty large projects out there in the real world, you might want to amend your statement from "Maven scales astoundingly poorly" to "I am astoundingly poor at scaling Maven".

It's not all wine and roses in the land of Maven, but it gets a whole lot of the job done, and done well.


You can add pretty much anything to do with CORBA to your list. Yes there are plugins for it, but they only work in the most trivial of cases.

The original article was helpful to clarifying for me why I have such a low opinion of maven - the project I was working on when Maven came out was a large complex codebase and we'd built lots of interesting things into our Ant build files. I could not work out how to ever do those sorts of things in Maven.


Badly written programs are far from an inevitable outcome with contextual tools. That is more a symptom of Maven's choice of a rather narrow context that has limited its appeal (that and all the ways it sucks ;-).


>- submitting code to a code review site like Gerrit.

Why would you want your build tool to do that?

>- generating code (for example, a parsed SNMP MIB that you want as a Java class so you can refer to it easily).

There are plenty of plugins to do that. If you want one that doesn't exist, write your own. It's not hard, and means this operation will be encapsulated in a structured, testable, reusable way. If you're generating code in an ad-hoc, specific-to-a-single-project way, you're doing it wrong.

>- integration with a tool like Sonar (yes, there's a Maven plugin. You ever used it?).

Yep, I've used it. It works fine.

>- code coverage analysis (yes, there's a Maven plugin. You ever used it?).

Yep, I've used it. It works fine.

>- FindBugs style analysis (yes, there's a Maven plugin. You ever used it?).

Yep, I've used it, it works fine.

>- interesting dependencies on external libraries (to pick an example from Ruby, the json gem was horribly broken at 1.4.2 and generations of projects have varying requirements for json < 1.4.2, json > 1.4.2, and many other worse things.

Huh? You can depend on a specific version, a range of versions, or a range with gaps in. You can't depend on two versions of the same library because it's impossible to set the classpath up like that, but that's a limitation of Java, not maven.

>- C code (through JNI or anything else, a perfectly reasonable thing to want to do).

There are ways to do this, I'll agree it's not pretty. If you want to use another build tool for those projects that include C code that's fair - it should be a minotiry of your projects.

>- deployment.

Not the appropriate tool for it.


I thought Maven was a build tool, shouldn't your continuous integration system put code into Gerrit?

We use Maven and it just works. We play with the idea to move to Gradle, but the effort is non trivial and the real benefits not clear.

We use Sonar. We use Clover for code coverage. We use PMD. We use Checkstyle. We use FindBugs.


- cross-platform C/C++ code and JNI libraries work just fine using the NAR plugin (was developed at CERN for this use case, IIRC). I've used this extensively over the last year to integrate legacy C++ libraries with our Hadoop jobs.

- code coverage / findbugs etc. are better done using something like Sonar. Again, this works just fine for us. You can also set up Sonar & Jenkins on your desktop in minutes and have a working analysis suite + web interface without centralising your builds.

And I assert that you're wrong on the IDE integration - Intellij appears to shell out to Maven for some things, but M2E in Eclipse is a completely different beast (and has some rough edges as a result, but can work well).


"interesting dependencies on external libraries (to pick an example from Ruby, the json gem was horribly broken at 1.4.2 and generations of projects have varying requirements for json < 1.4.2, json > 1.4.2, and many other worse things."

This seems like a java problem more than a maven problem. In fact, I don't really know what you could do about this. Maybe OSGi has a solution.


Um... his example is a Ruby library. It's a totally language-independant problem.


"The only thing your IDE actually needs to get from the Maven POM is to understand where your source code is, what you depend on and where it is, and how to run your tests."

And how does it get that from ant? That seems such a small thing. "Everything else they do...." must be so important. I don't think it is. I think the most important thing is that when developing in the IDE I have a reasonable certainty that when it builds on the CI server that its going to do the same thing. The next most important thing is that our team can develop using the IDE each prefers (or vim if they want). Maven is the only "project description" that is understood by every IDE and also runs from the command line.

"Everything else they do with command line calls, just like Ant".

Not so. For example, both eclipse and IntelliJ, when faced with a merge-war project, will set up a project definition that provides the same behavior as running maven, but without running maven. Modifying a resource in the common war project causes that file to be deployed to any running targets. Its instantaneous and automatic. Its the difference between an Integrated Development Environment and a text editor.

Everything else, don't use maven. Maven is a tool for building java.

Our tools for deployment make maven look like "hello world". I wouldn't use maven to deploy. Likewise for submitting code to anything. I use maven to build deployable targets from java and to upload them to a repo. End of story.

Basically, if it hurts when you do that, don't do that. I use bash on my build server. Somewhere in the middle, bash runs maven.

So how would I handle generating some code from another format? Depends what it is. One fellow said reading from a database for example. Well before I ran maven, I'd run the program that generated the java files, and then I'd check those files into source control so that we know what exactly got built. Then I'd run maven. If it was generating java from a text file, I'd probably have it as an Ant task in my IDE, and whatever got generated, I'd check that in too. Sometimes I've gone as far as to write an IDE plugin that builds the file automatically.

Checking in generated files? Isn't that an excuse? Well, no, not if you want to guarantee to be able to build it in 18 months time. I've worked at a place where they couldn't even build an 18 month old product to support a customer because the build system itself wasn't versioned!


A correction I should note; the broken json gem was 1.4.3.


Thank you for espousing the Maven opinion. I would take your argument a step further and explain that mvn fits into common development workflows much the same tr fits into the word-counting example. Mvn is composable.

Let me illustrate what we do at work to explain. We use Jenkins as a build server and a hosted git repository. Every accepted pull request to mainline-dev is picked up by Jenkins, Jenkins runs mvn test on the commit, if the build passes, Jenkins integrates the change into mainline-stable, and Jenkins runs mvn deploy to get the latest build on a mainline-stable server.

Setting up this workflow required little customization because mvn's output was well-defined and designed to be composed within other environments, and jenkins is one common place that understands it. So are the IDEs at your work. So is the next person to tweak the environment who can look at docs to figure out what's going on. It's no different than how sed knows how to interpret tr's text output.

Does this workflow work for everyone and every language? No, not at all. Does mvn the tool work for everyone and every language? No. But I see it as an example how mvn, a build tool, fits into larger process and is a composable tool the author lauds.

P.S. The biggest benefit for our shop is twofold:

1) Dependencies get resolved automatically in all environments. Unlike my last gig, developers run the same version of libraries as the prod machines do.

2) Developers run the same test cases locally as jenkins does. We've only had one build break.


    And then the person that wrote them leaves and we're fucked.
Where in the article does he say in-house tools are better? His point is about tool composability. Just because you haven't run into the wall he describes Maven having yet doesn't mean it doesn't exist. He says as much in fact. He recommends starting with maven till you outgrow it which seems perfectly reasonable.


I think you missed the point. The problem with comparability is that you have the freedom to compose things however you want to. It's not exactly uncommon for "composable" build systems to be all but inscrutable to the next guy.

The consistency of an opinionated build tool does provide some not insignificant benefit.


s/The problem with comparability/The problem with composability/


This is so right that I feel like I live in a different universe from someone that wants to write code in their build system. If you do write your own build system, make sure it outputs a pom.xml file so I can still use maven.


You can like maven or hate it, but why can't it be a bit simpler?

e.g. take this selenium install instructions (http://seleniumhq.org/docs/03_webdriver.jsp)

Ruby:

    gem install selenium-webdriver
Java (with Maven):

   <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0
                 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance
                 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd>
        <modelVersion>4.0.0</modelVersion>
        <groupId>MySel20Proj</groupId>
        <artifactId>MySel20Proj</artifactId>
        <version>1.0</version>
        <dependencies>
            <dependency>
                <groupId>org.seleniumhq.selenium</groupId>
                <artifactId>selenium-java</artifactId>
                <version>2.28.0</version>
            </dependency>
            <dependency>
                <groupId>com.opera</groupId>
                <artifactId>operadriver</artifactId>
            </dependency>
        </dependencies>
        <dependencyManagement>
            <dependencies>
                <dependency>
                    <groupId>com.opera</groupId>
                    <artifactId>operadriver</artifactId>
                    <version>1.1</version>
                    <exclusions>
                        <exclusion>
                               <groupId>org.seleniumhq.selenium</groupId>
                            <artifactId>selenium-remote-driver</artifactId>
                        </exclusion>
                    </exclusions>
                </dependency>
            </dependencies>
        </dependencyManagement>
   </project>
Then run

   mvn clean install


Sounds like they've cocked up the jars they've produced; you should never have to use exclusions, and it's possible to have a dependency that can be satisfied multiple ways with a default, so you shouldn't need to choose the driver separately if you don't want to. Much of that xml file is what already exists for your project. So the fair comparison is with the section: <dependency> <groupId>org.seleniumhq.selenium</groupId> <artifactId>selenium-java</artifactId> <version>2.28.0</version> </dependency>

So: you need a groupId; we've learnt through painful experience that this is a good idea to prevent collisions rather than just using the name. That said, your tool should autocomplete it if there's only one option.

You need to specify a version; this is 1000% the Right Thing. Again, your tool will give you a list to choose from.

And yeah, it's a bit of a verbose way to specify those three pieces of information; the point is for it to be easy to automatedly manipulate the pom file.


Exclusions happen, when you need to make do with libraries that have different release schedules or are poorly organized but critical for your current priorities, needs and time constraints. One should see exclusions pretty much as Technical Debt.

Maven becomes brilliant when you start dealing with a large number of modules and profiles, and becomes more tedious when you pass a certain complexity threshold, usually when you have multiple layers of compile-time code generation going on top of each other.


One is reproducible. One isn't. YMMV.


Well in ruby you could use bundler and it becomes

gem 'gem-name' # in Gemfile

$ bundle install


Until you want to do it on a system you just want binaries.

Or until you need to guarentee the version of the library you're bundling

Or you want to run on something other than a MAC-in-crap, like Linux.

RVM has the same problems.

In my opinion, one is for play, and one is for work. If you just want to fuck around and spew code in one long controller that looks like spaghetti, and you don't want to worry about reproducability or quality guarantees or modularity then Ruby build tools are fine to use.

It's incredibly frustrating to hear about people complaining about how tool X doesn't do task Y. They could just STFU and write the plugin.

There is really only one type of plugin that wouldn't work well in Maven, and it's when for some reason you're task doesn't fit into it's "life cycle" pattern. For example, you want something running in the background when you edit SASS, LESS, TypeScript files and you want some processor to just run and deploy in the background continuously. In this scenario, you could keep the Mojo API, but you would have to lose the Maven Framework.

Each tool for it's job.


> Or until you need to guarentee the version of the library you're bundling

gem "thing", "3.0.0.beta3"

gem 'rails', :git => 'git://github.com/rails/rails.git', :ref => '4aded'


It does guarantee the version, and I'll ignore the rest of the trolling.


Putting a concrete plugin version into your pom.xml helps with #1. It's solved 95% of the issues we were having with Maven.




Consider applying for YC's Summer 2026 batch! Applications are open till May 4

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

Search: