Make was quite a handy tool in its day. Ant has revolutionized automated builds. Maven has taken build transparency and automated development and deployment to a whole new level. If you haven't caught the maven bug yet, it's time to take a deeper look now that the next generation—Maven 2—is available. If you're already working with Maven but are interested in M2, scroll down a little and get started!
Why? Ant Works for Me!
If you hang out with the types of developers I hang out with, you have probably come into contact with a John at some point. John is a friend and coworker—a mentor. as a matter of fact. One word can sum up his reaction the first time I introduced him to Ant several years ago. Why?
John loved his make files, and quite frankly, he could build a kitchen sink with make and a few shell scripts. It took several months for me to convince John that Ant was more than a poor man's make. It took more than a simple comparison. John just didn't get it because Ant changed the playing field. Ant was powerful because it expanded automated builds beyond what they had ever been before. Now that he's taken the Ant plunge, Now, after taking the Ant Plunge, John can build the same kitchen sink in half the time. The increased productivity is easily explained. John no longer has to create pipes, faucets, and drains by hand. Instead, he uses the prebuilt ones that are readily available.
Maven is to Ant what Ant was to Make. Maven supercedes Ant. Maven provides the same functionality that has been traditionally present in a build tool but introduces new concepts that haven't been considered in previous build systems. So, what are these new concepts? Why is Maven so great? You should explore.
Understanding Maven Concepts
Unlike Ant, Maven projects do not require the development of one or more build files. Instead, Maven introduces the concept of a project descriptor, or POM. The POM (Project Object Model) describes the project, providing all of the information needed to perform a series of prebuilt tasks. These tasks, or goals as their are called in Maven, use the POM information to execute appropriately. When necessary (almost never for a typical project), plugins can be developed and utilized across multiple projects in the same manner as prebuilt goals.
A project's POM consists of very basic information about a project, such as the type of project (a jar library, war, and so forth); however, this simple concept of centralizing this information into a single XML file is very powerful. As you will see, by centralizing this information, Maven is able to provide goals that build, assemble, deploy, document, report, produce metrics, and do much more with your project. The POM is often referred to as pom.xml.
Goals, What not How
By introducing a project descriptor, Maven requires a developer to provide information about what is being built. This differs from traditional build systems (like make or ant) where developers instruct the system how to build. This change eliminates the need for developers to rebuilt the same functionality over and over again.
Imagine how many people in the world have written a compile target for ant. Think you're the only one to write a war target? Think again! By providing customizable goals, this duplication is eliminated and developers can focus on developing business logic rather than developing a build system. In maven, once your POM is defined, add a source file and run the compile goal. Boom! Compiled!
Utilize Best Practices
Have you ever checked out a clean version of a project from source control only to spend the next 15 minutes trying to figure out where the source code is located, how the build file pieces everything together, and what version of jdom is supposed to be in your class path? If not, you're lucky. You either only work for with projects that all have the same build practices or you have some great documentation. For the rest of us, there's Maven.
Maven does not enforce best practices for projects. It strongly supports them. Typically, you will find that Maven projects are very consistent in their project setup. They mirror the same directory structures and utilize the same goals. This consistency, along with the centralized dependencies (discussed below), makes it easy to check out a project and work with it immediately. Want to find the Java source code for a Maven project. If it follows conventions, look under src/main/java. Looking for the Java test code? Take a peek at src/test/java. Want to build a distribution? Check out the assembly plugin and run assembly:assembly. How about running the tests? The test goal should do it.
Of course, not all projects are exactly the same, and any build tool needs to be customizable. Maven supports projects with unconventional layouts. Even in these instances Maven can help. Directory locations and custom goals can be discovered by simply looking at the POM.
Configuring dependencies within a build system is often a nightmare. If your build depends upon specific library locations, each developer must maintain the same directory structure and libraries. Libraries that are required for multiple projects often get duplicated throughout the file system. Another alternative, checking dependencies into the source code repository, requires placing compiled binaries, which may be under development themselves, into the repository.
Maven introduces the concept of centralized managed dependencies. In Maven, the build system itself is responsible for downloading and adding dependencies to the appropriate classpath. Projects define their external dependencies in their POM. Maven's dependency mechanism is then responsible for retrieving the dependency when necessary.
To optimize performance and reduce storage requirements, Maven stores all retrieved dependencies within a single repository. When it encounters an unknown dependency, it searches its external repositories, downloads the dependency, and places within its local dependency.
What's New in Maven 2
Maven 2.0 is a rewrite of the popular Maven application to achieve a number of goals, and to provide a stable basis to take it into the future. It is currently available as a Technology Preview (from the Maven 2 Web site).
Maven 2 project descriptors allow for the scoping of project dependencies. Scopes allow for dependencies that are not needed in every environment. The four available scopes are:
- compile indicates that the dependency is required for compilation and execution. These dependencies often will be provided with distributions and bundled with deployments.
- provided indicates that the dependency is required for compilation but should not be bundled with deployments and distributions. These dependencies should be provided by an external source (typically a container) during runtime. Most Java extension API dependencies (such as servlet-api) will be defined in the provided scope.
- runtime indicates a dependency that is not needed for compilation but is needed at runtime. Many runtime dependencies are implementations of other APIs. Often, these dependencies are injected or configured. A good example of a runtime dependency is a JDBC driver implementation.
- test dependencies are required for the execution of unit tests. These dependencies are not made available in distributions and deployments.
Maven 2 introduces the concept of Transitive dependencies. Direct dependencies are those upon which a project explicitly depends. Typically, a project will not compile without direct dependencies. Transitive dependencies are those which direct dependencies themselves depend upon.
Consider the following example:
+-- mavenized-webapp + -- struts + -- commons-logging + -- castor
In this example, the mavenized-webapp project has two direct dependencies, Struts and Castor. In this example, the commons-logging dependency would be considered a transitive dependency because it is not directly required by mavenized-webapp.
When utilizing Maven 1, transitive dependencies must be explicitly defined as a dependency to be included within testing and execution classpaths and distributions. Maven 2's dependency mechanism will take care of determining transitive dependencies. This eliminates the need for the dependency to be defined within the project descriptor.