Multi-Module Projects

Developers that are familiar with the version scheme of the Spring Framework will notice that each module has the same version number. For example:

spring-beans-4.2.1.RELEASE.jar

spring-context-4.2.1.RELEASE.jar

spring-core-4.2.1.RELEASE.jar

... etc ...

This is because the Spring Framework is configured as a multi-module project. This concept isn't necessarily tied to a particular build tool, but I think that it is fair to say that it is a feature of Maven that is used quite often by developers.

Similar to the Spring Framework, the Liferay Faces project was originally built as a multi-module project in which each artifact had the same version number. For example:

liferay-faces-alloy-4.2.5-ga6.jar

liferay-faces-bridge-api-4.2.5-ga6.jar

liferay-faces-bridge-impl-4.2.5-ga6.jar

liferay-faces-portal-4.2.5-ga6.jar

liferay-faces-util-4.2.5-ga6.jar

This was achieved using a parent POM like the following:

liferay-faces/pom.xml

<project ...> <version>4.2.5-ga6</version> ... <modules> <module>alloy</module> <module>bridge-api</module> <module>bridge-impl</module> <module>portal</module> <module>util</module> </modules> ... </project>

I think that there are development scenarios in which it might make sense to create a multi-module project. But as with most design decisions, there are typically benefits and drawbacks.

Benefits of a Multi-Module Project

The main benefit of a multi-module project is convenience:

Convenient Development: We used Maven to layout a multi-module project structure which provided a convenient development environment. When we first started the Liferay Faces project, we had only a handful of jar/war modules and a single master branch. As we added additional jar modules and demo war modules, it was easy to expand the development environment.

We used Maven to layout a multi-module project structure which provided a convenient development environment. When we first started the Liferay Faces project, we had only a handful of jar/war modules and a single master branch. As we added additional jar modules and demo war modules, it was easy to expand the development environment. Convenient Testing: Since all of our modules were located in the same multi-module project structure, it was convenient to add Selenium tests to that same structure.

Since all of our modules were located in the same multi-module project structure, it was convenient to add Selenium tests to that same structure. Convenient Releases: Performing releases was easy thanks to the maven-release-plugin.

Performing releases was easy thanks to the maven-release-plugin. Convenient Deployment: It was also convenient for our customers and community since they could specify the same version number for each Liferay Faces module in their pom.xml or ivy.xml descriptors.

It was also convenient for our customers and community since they could specify the same version number for each Liferay Faces module in their pom.xml or ivy.xml descriptors. Convenient Version Control: We were able to use a single liferay-faces Git repository for managing the source code.

Drawbacks of a Multi-Module Project

As we added support for new versions of Liferay Portal and new versions of JSF, our single Git repository ended up with seven different branches. In order for developers to know which version corresponded to their environment, they had to read the official documentation for Understanding the Liferay Faces Version Scheme.

As an illustration of the drawback of having all modules on the same release schedule, consider a team that is running a race hand-in-hand (or arm-in-arm). The team can only go as fast as the slowest runner. Although the multi-module project structure was convenient, it became increasingly difficult to get releases done in a timely manner. For our GA6 release, we added lots of new components to Liferay Faces Alloy (as shown in the Liferay Faces Showcase). But since liferay-faces-alloy.jar had the same version number as all the other modules, we were not able to release simple fixes for other modules since all of the modules had to be completed and released on the same schedule. In order to compensate for this drawback it was necessary to release a series of patches for Liferay Faces GA5 in the form of jar modules that were deployed alongside our GA5 modules.

An Extreme Alternative If the benefits of a multi-module project (within a single Git repository) do not outweigh the drawbacks, then an extreme alternative would be to have each module in its own Git repository. This provides the ability to independently version each module and to have each module on a separate release schedule.

Compromise for Liferay Faces

In order for us to support our customers and community in a more agile manner, it is necessary to independently version each library (jar) module. However, each demo module (like jsf2-portlet.war) does not need to be independently versioned. This will allow us to support separate release schedules so that we won't have to rely so heavily on patch jars. As a result, we split the single liferay-faces Git repository into multiple Git repositories.

New Git Repositories

Git Repository Description liferay-faces-alloy Multi-module Maven project structure that contains the liferay-faces-alloy.jar library module, liferay-faces-alloy-reslib.jar, and associated demo war modules. liferay-faces-bridge-api Single-module Maven project structure that contains the Bridge API jar for JSR 378. liferay-faces-bridge-ext Single-module Maven project structure that extends Liferay Faces Bridge to support Liferay Portal. liferay-faces-bridge-impl Multi-module Maven project structure that contains the Reference Implementation jar for JSR 378, the Bridge TCK, and associated demo war modules. liferay-faces-metal Currently a placeholder for an upcoming JSF component suite based on Metal.js for use with Liferay 7.0. liferay-faces-maven Multi-module Maven project structure for Maven plugins. liferay-faces-portal Multi-module Maven project structure that contains the liferay-faces-portal.jar library module as well as associated demo war modules. liferay-faces-util Single-module Maven project structure that contains the liferay-faces-util.jar library module.

New Dependency Tree

One of the benefits of splitting up our single Git repository into separate Git repositories is that the dependencies between modules are more clearly seen, as shown in the following diagram:

(click the preview to see a larger version)

Conclusion

Although the multi-module project structure was convenient in many ways, the benefits did not outweigh the drawbacks. We now have the ability to independently version each jar module in order to support separate release schedules. In addition, we will be able to better adhere to the rules of Semantic Versioning.

[UPDATE: 2016/03/31, see the follow-up blog post titled New Liferay Faces Version Scheme].