Like buildings, software usually a deviation of a standard structure. The architect chooses the structure his design will be based upon. After making design adjustments to the structure to cater the requirements, the architect supervises the builders. Like a building architect, the software architect supervises while walking around in the structure during the build.
Software projects can get so large and complex that the architect can not posibly monitor all the code all the time. This is where te tooling comes in. In this post, I will explain how to use Checkstyle to automatically monitor the basic architectural integrety of the software.
When designing software, we usually start of with drawing high level building blocks on a piece of paper. In most of my sketches, these building blocks map to Java packages in the code, and the arrows between the blocks represent communication paths or method calls between the packages.
Interfaces and calls between packages are an important part of the architecture or design. One of the ways to monitor design integrity is to monitor which packages are using other packages, and the way packages interact.
Packages are almost a Java-specific term for what other languages call “modules”, or “libraries”. The way these packages are grouped in graphical representations of the design is very often layer-like. For more information on layers, maybe you should read about 3-tier architecture.
The word “Tier” is a more exact term than layer, but to keep things less confusing by introducing another term, I’ll stick with the word “layer”.
As with any design, it is important to stick to the plan. Software developers have no physical boundaries to access the different layers of the software. This means that during development, layers can be interconnected in a way that was not intended by the architect. These connections are called “Layer violations”. One of the important tasks for the architect is to prevent these violations.
To prevent developers making layer violations, the design should be simple and clear to the developers. In essence, developers should not see the need to violate the layer access rules. Make the right thing to do, the easy thing to do.
If layer violations are a common practice in a project, the architect needs to investigate the reasons for these violations, and may need to reconsider the design or the layer access rules.
Eliminating layer violations will:
- Reduce complexity of the software
- Prevent circular dependencies
- Reduce vulnerability to exploits
- Improve code reusability
When software projects become too large to monitor each line of sourcecode by hand, tooling is needed to monitor these Layer Violations. One of the tools which is able to do this for Java code is CheckStyle. The Checkstyle module we use to monitor layer violations is called “Import Control”.
Suppose we want to create a simple (java web) application. This application consists of some screens for users to enter data, a bunch of business rules for processing this data, and data storage.
The generic way to solve this problem is to logically group the functionality into packages. The following packages will be used in our example application:
- Frontend – Contains the screens (this can contain Wicket, Tapestry or JSP techoligy for instance
- Service – Contains the business logic for processing the data. The servicelayer usually contains the highest level of abstraction, because it uses the core and data access layers to get things done.
- Core – Data object which represent entities in the system. These are usually beans or POJO’s, and represent real-world things like “User”, “Order” or “Invoice”.
- Data Access – This layer has the responsibility of storing Core objects into the database, and retrieving them.
The green arrows between the layers represent normal relationships, or method calls, if you like. The Frontend layer uses the service layer. The Service layer uses the Data Access layer. All layers need to pass Core objects to eachother, so they all have to be able to use the Core layer.
On the right side we see a red arrow from the Data Access layer to the Frontend layer. This arrow is an example of a so called “layer violation”. Having a relation to the Frontend layer makes the Data Access layer dependant on the Frontend, and could also lead to circular references.
Checkstyle is a program which can parse Java source code, and create a list of coding style violations and architectural errors. It also has a maven plugin, which we are going to use in our example project to get a report on layer violations.
First, we need to add Checkstyle to the project. Layer violation monitoring was added to Checkstyle in one of the later releases. To make sure that we have the correct version of Checkstyle, add the folowing dependency to your Maven (1.0) project.xml:
<dependency> <groupId>checkstyle</groupId> <artifactId>maven-checkstyle-plugin</artifactId> <version>3.0.1</version> <type>plugin</type> </dependency>
Should you want the Checkstyle report to be automatically included in the generated Maven site, you can optionally add
To the <reports> section of the project.xml file.
Now that we have added Checkstyle to our Maven configuration, we need to configure Checkstyle to check our layer violations. Checkstyle can check a lot more, but we’re only using it to check Layer Violations for the sake of this article.
We need to tell the Maven Checkstyle plugin where it can find it’s configuration file. Add the following line to the project.properties in the root of your maven project:
#Checkstyle maven.checkstyle.check.tests=false maven.checkstyle.fail.on.violation=false maven.checkstyle.properties=checkstyle-config.xml
Next, create a checkstyle-config.xml in the root of your project which looks like this:
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE module PUBLIC "-//Puppy Crawl//DTD Check Configuration 1.2//EN" "http://www.puppycrawl.com/dtds/configuration_1_2.dtd"> <module name="Checker"> <property name="severity" value="warning"/> <module name="TreeWalker"> <module name="ImportControl"> <property name="severity" value="error"/> <property name="file" value="checkstyle-import-control.xml"/> </module> </module> </module>
As you can see in this configuration file, checkstyle will look for a checkstyle-import-control.xml file containing the Layer access rules.
An example of this file which would match our example would look like this:
<?xml version="1.0"?> <!DOCTYPE import-control PUBLIC "-//Puppy Crawl//DTD Import Control 1.0//EN" "http://www.puppycrawl.com/dtds/import_control_1_0.dtd">
<!—allow access to utility libraries --> <allow pkg="java"/> <allow pkg="org"/> <allow pkg="sun"/>
<subpackage name="frontend"> <allow pkg="com.rolfje.example.frontend"/> <allow pkg="com.rolfje.example.service"/> <allow pkg="com.rolfje.example.core"/> <allow pkg="javax.servlet"/> </subpackage>
<subpackage name="service"> <allow pkg="com.rolfje.example.service"/> <allow pkg="com.rolfje.example.dataaccess"/> <allow pkg="com.rolfje.example.core"/> </subpackage>
<subpackage name="dataaccess"> <allow pkg="com.rolfje.example.dataaccess"/> <allow pkg="com.rolfje.example.core"/> </subpackage>
<subpackage name="core"> <allow pkg="com.rolfje.example.core"/> </subpackage>
There are a few things to note in this configuration file:
- It is allowed to use java.*, org.*, and sun.* packages abywhere in the code. This is to allow normal usage of java.util.List for instance.
- The frontend is a web frontend in this example, and accesses javax.servlet. Note that the service, backend and core layers are not allowed to use servlet classes.
- Packages are allowed to access themselves. This is done so that sub-packages made by developers are not immediately detected and seen as a layer violation.
- There are no nested subpackages in this example. You can nest subpackage elements if you need to.
Having configured everything, you can now run “maven checstyle:report” to see how your code is matching your design. If you run a “maven site”, then the Layer Violations will be visible as a report in the left menu.
You may also want to checkout the Checkstyle eclipse plugin, which will visually mark the violations in you sourcefiles and add them to the “Problems” view. It will help you to find and fix the violations much quicker.