How to replace a build module with Veripacks
Compare the two trees below. In both cases the goal is to have an application with two independent modules (frontend
and reporting
), and one shared/common module (domain
). The code in frontend
shouldn’t be able to access code in reporting
, and vice versa. Both modules can use the domain
code. Ideally, we would like to check these access rules at build-time.
On the left, there’s a traditional solution using Maven build modules. Each build module has a pretty elaborate pom.xml
, e.g.:
<?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'> <parent> <artifactId>parent</artifactId> <groupId>org.veripacks.battle</groupId> <version>1.0.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> <name>Veripacks vs Build Modules: Frontend</name> <artifactId>frontend</artifactId> <dependencies> <dependency> <groupId>org.veripacks.battle</groupId> <artifactId>domain</artifactId> <version>1.0.0-SNAPSHOT</version> </dependency> </dependencies> </project>
On the right, on the other hand, we have a much simpler structure with only one build module. Each application module now corresponds to one top-level project package (see also this blog on package naming conventions).
Notice the package-info.java
files. There, using Veripacks, we can specify which packages are visible where. First of all, we specify that the code from top-level packages (frontend
, reporting
and domain
) should be only accessible if explicitly imported, using @RequiresImport
. Secondly, we specify that we want to access the domain
package in frontend
and reporting
using @Import
; e.g.:
@RequiresImport @Import('org.veripacks.battle.domain') package org.veripacks.battle.frontend; import org.veripacks.Import; import org.veripacks.RequiresImport;
Now, isn’t the Veripacks approach simpler? There is still build-time checking, which is possible by running a simple test (see the README for details). Plus, you can also use other Veripacks features, like @Export
annotations, which is a generalized version of package-private scope, taking into account package hierarchies. There are also other benefits, like trivial sharing of test code (which is kind of hard with Maven), or much easier refactoring (introducing a new application module is a matter of adding a top-level package).
The immediate question that arises is – what about 3rd party libraries? Most probably, we’d like frontend-specific libraries to be accessible only in the frontend
module, and reporting-specific ones in the reporting
module. Well, not supported yet, but good news – that will be the scope of the next Veripacks release. You can view the example projects on GitHub.
Reference: How to replace a build module with Veripacks from our JCG partner Adam Warski at the Blog of Adam Warski blog.