Using Maven for Large Projects
Having just recovered from the "culture-shock" from converting from Ant to Maven, I'd like to pass on a few words about the experience.
At first glance, Maven seems quite complicated. Rather than writing your own targets, Maven has dozens of its own, already written for you. Then comes the realization that all of the stuff you normally write in Ant scripts is there already; for many projects, you don't need to write a thing.
Where It's At
What you do need to do is follow a specific pattern as to where you put what. Source should go in "src/java", for example. Output jars go in "target", and so forth. These directories can be overridden if you need to, but it's not very difficult to simply adapt to the Maven structure, and it makes for a good standard accross Maven projects.
One special type of location for Maven are "repositories." There are "local" repositories, where Maven maintains versioned copies of all jar files required by your projects, and remote (possibly public) repositories, where versions of jar files reside ready for use in projects.
The Maven project definition (Project Object Model file, or POM) tells Maven what jar file dependencies are required for the specified project, and it will search a list of remote repositories (usually including http://www.ibiblio.org/maven) for the necessary jar files, and download them to the local repository (once) when required. This information is normally stored in project.xml.
All for One
The other concept that makes a lot of sense, once you get used to it, is "one project, one artifact." Simply put, this means that any one Maven project produces a single "artifact," or result file. This is usually a war file (for Web applications) or a jar file, either executable or not. Back when I was using Ant, I've found myself creating a couple of different targets that built different parts of an application—say, one to create the dependency jar files, and another to produce the finished webapp.
The terminology for Maven is not much different from Ant. Instead of "targets," Maven talks about "goals." Each collection of source files designed to produce a certain resulting file (artifact) is a "project," just like Ant. When you see the scripting in Maven (if you ever do), it's a lot like Ant; in fact, virtually every Ant task can be used within Maven scripts, with minor, if any, changes.
Chances are good, however, that you'll not need to write as much custom scripting for Maven as you did with Ant. You'll want to browse the list of available plugins on the Maven site (http://maven.apache.org) to get familiar with what's out there.
Plug It In
Maven is oriented around the concept of a plugin, which, in short, allows you to add custom goals to Maven. A large collection of existing plugins has every goal that most projects need, meaning you have exactly no work to do—other than a bit of learning, that is. For the occasion where you do need to do some custom work, you can create a maven.xml file that is specific to one project, just like a build.xml file for Ant. For larger projects, however, you'll likely want to re-use your custom goals, and creating your own plugin is the answer for this. A plugin is a Maven project just like any other, although it may not have any Java code associated with it if all you need are custom goals without any code. Once a plugin is created, you can "deploy" it to a repository, and the rest of your team can type a single command to download and install it on their local machine.
Plugins, just like every other component Maven handles, are versioned, so you can release updates to your plugin in an organized and controller manner.
Versions, Versions Everywhere
Maven is organized around the concept of versions, for plugins, projects, and dependencies. If you establish a reasonable version numbering mechanism, after a while you'll wonder how you ever got along without Maven.
For example, your primary project might start with a version 1.0, let's say. It, in turn, depends on service-database-1.0.jar. You simply declare this dependency in the project.xml, and Maven takes care of making sure that service-database-1.0.jar is in the classpath when you build your project. If it's not already in the local repository, it searches all known remote repositories to try to find it, and downloads it automatically.
Later, you find a bug in service-database-1.0, and service-database-1.0.1 comes into being. Again, when your project is ready, you simply edit project.xml, increment the version of your main project to (say) 1.1, and build. Now, both 1.0 of the project and 1.1 are able to be built—so in the (unlikely!) event you, ahem, introduced an unintentional feature (a bug) in 1.0.1 of service-database, rolling back is very easy as well. Another month passes and an API change is made to service-database-1.0.1, making it now service-database-2.0. Your existing projects, all of which rely on service-database-1.0.1, with its older API, still work just fine. As they are upgraded to the new API, then simply declare the new dependecy on 2.0. No upheavals, no whipping the rug out from under existing projects when something changes.
Take a SNAPSHOT
In a team development situation, however, sometimes things move a bit faster than the above scenario can easily handle. If bug fixes and enhancements are coming thick and fast, you may want a way to say "this project depends on the very latest available service-database, whatever that is." This is a good spot to use a SNAPSHOT. When creating a jar file for our service-database, we have the option to build and deploy either a versioned jar (for example, 2.0), or a SNAPSHOT. Snapshot is a special version that indicates a current development copy. Unlike regular versions, Maven will check for a new SNAPSHOT version in a remote repository for every build. For "normal" versions, once Maven has downloaded 2.0 (for example), it never tries to get a "new" 2.0. Once 2.0, always 2.0—to get changes, you'd need to go to 2.0.1 (or some other version). With a SNAPSHOT version, though, Maven will automatically fetch the latest SNAPSHOT every time you build your project. For rapidly moving code, this can be a necessity, particularly in a team environment.
Maven supports unit, integration, and functional tests. For unit tests, the default is JUnit, making the popular test framework trivial to put to use. Tests are kept (again, by default) in a seperate source tree, and need not be included with your deployed code (or jar).
Maven's default setup is to actually refuse to build the project artifact (jar or war) if all available unit tests are not running successfully. You can override this behavior easily, of course, but it's a good safety for production code.
Enough has been said about the absolute requirement for good testing that I won't repeat the sermon here, other than to say that Maven provides the ideal backbone and structure for a comprehensive test suite at every level.