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.
Adam
comments powered by Disqus