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.:
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 | <? xml version = '1.0' encoding = 'UTF-8' ?> < 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.:
1 2 3 4 5 6 | @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.