Home / Java Patterns and Pitfalls     frequal.com

A Good Maven Project Has Many Modules

Any non-trivial maven project should be decomposed into multiple modules. Splitting your projects is a maven best practice that provides numerous benefits: You see the most from these benefits when your project is wide and shallow, with as few modules depending on others as possible.

Faster Build Times

Is your maven build time as fast as you would like? I didn't think so.

Maven has a command-line argument "-T" which lets you specify the number of threads to use. A common choice is "-T 1C", which instructs maven to create one thread per core. In a multi-module project, maven can build modules in parallel on different threads, as long as those modules dependencies are already built. The simplest example would be this project:

Module A depends on modules B and C. Modules B and C can be built simultaneously on separate threads, and then finally module A can be built. If all three modules take the same amount of time to build, then you've already cut your build time by 33%. You can probably imagine that in a large project with dozens or even hundreds of modules, you can see major speedups as long as the modules are mostly independent. In one of our larger projects, the parallel build time is just over 1/3 the duration of the non-parallel build thanks to heavy modularization.

Cleaner Code

Splitting your code into modules forces you to think about what parts are independent. This is a key part of architecting a larger project. You already think about how to group functionality into packages. Splitting into maven modules makes you think further about dependencies. IDEs make it easy to use code from other packages, so you can inadvertently end up with lots of inter-package dependencies, even circular ones. But since maven modules have explicitly declared dependencies, you'll have to think about which modules depend on which others more clearly.

To achieve good design (and speed up builds), you'll want to make sure your code is split into a bunch of independent modules. Most modules should have only a very small number of dependencies. You may have a core set of POJOs used for communication bundled in one lightweight module, but that should be about it for widely shared dependencies. You'll also likely have a small number of modules that pull together many others, for example a RESTful resource or the main UI module. (If you choose a microservice approach you may end up with many smaller RESTful resources.)

As you are writing new code, look for chunks of logic that are separate from the rest. Start with fundamental Java best practices like defining an interface for that functionality, creating an implementation of that interface, and only accessing the functionality through the interface. This puts you in a good place to modularize. The interface can go in an API module, and the implementation can go in its own module.

Easier Reuse

By thinking about and splitting your code into maven modules, you also gain more opportunities for reuse. If you have a small module with a specific task, having it as a maven module allows you to easily declare it as a dependency from another module, making it available quickly and easily. And if you share your maven dependencies via a repository, other people can reuse them too. And if you follow the API/implementation split described above, it is very easy for people to look at your module's interface without becoming bogged down looking at implementation details.


By following the maven module guidelines above, you will end up with better organized, faster-building, more reusable code.
Last modified on 15 Mar 2021 by AO

Copyright © 2024 Andrew Oliver