- Introduction to AU and jQA and software architecture
- Use Cases
- UC Component Dependencies
- AU layer dependency checks
- jQA layer dependency checks
- jQA layer definitions by PlantUML
- jQA architecture test execution
- jQA define known technical debt
- jQA define the layering constraint
- UC Class in wrong package
- UC Component Dependencies
This project was started as a copy of the ArchUnit Example project (cf. README.md). It’s purpose is the comparison of ArchJunit (AU for short) with software architecture testing by jQAssistant (abbreviated by jQA). We make use of the rich set of AU samples and try to set up a similar test in jQA to show the strengths and weaknesses of both approaches different use cases.
The following use cases are compared in detail:
-
UC Component Dependencies
-
UC Class in wrong package
Software architectures usually are composed of layers, or shells around a core, or components in general. In Java the components may be implemented as separate build units (JARs), or simply as packages - or as build units containing particular packages. It is very uncommon and inconvenient to have packages which are spread to different JARs (at least beyond a common root package). The architecture describes the desired component model and the allowed dependencies between the components. Technically there are only dependencies (imports) between classes, but this model can be reduced to dependencies between packages: A package A is dependant on package B if any class in package A or in a sub-package of A imports a class from B (or a sub-package of B).
The sample architecture contains three layers
-
controller
-
service
-
persistence
AU tests the layering by the following Test cases
link:src/test/java/com/tngtech/archunit/exampletest/LayerDependencyRulesTest.java[role=include]
-
Classes in the
service
package should not accesscontroller
classes -
Classes in the
persistence
package must not accessservice
classes -
Classes in
service
should only be accessed by classes fromcontroller
classes and otherservice
classes.
The jQAssistant part is described in detail by (and taken in large parts from) two blog posts
The desired architectural model is given in a PlantUML section of src/doc/architecture/05_building_block_view.adoc describing the jQA layer dependencies.
link:doc/architecture/05_building_block_view.adoc[role=include]
In this case there are no predefined rules in jQA which allow to test the architectural layering. The comparison of the model with the implementation is performed by several queries in jqassistant/structure.adoc.
The jQA helper query to compute package depth assigns the package level (depth in the package containment tree) to each Java package.
link:jqassistant/structure.adoc[role=include]
-
Find all Java packages
-
Compute package hierarchy as array
splitted
-
Assign the level (depth) to each package as the length of the
splitted
array.
The query in jQA helper query to make transitive package dependency explicit then adds a an additional DEPENDS_ON
relationship to
parents of a package P from other packages up to the same level of the source package.
link:jqassistant/structure.adoc[role=include]
Finally the query in jQA constraint to find architecture violations finds all packages which violate the architecture model.
link:jqassistant/structure.adoc[role=include]
-
Matches all packages from PlantUML with allowed dependencies
-
matches all Java packages
-
and
-
finally find packages which have a
DEPENDS_ON
relationship from <2> but are not covered by theMAY_DEPEND_ON
relationship from <1> (note thatp3
andp4
seem to be switched as compared top1
andp2
to do the trick). -
Will exclude allowed exceptions (cf. jQA define known technical debt)
-
Returns the matches (cf. jQA define the layering constraint).
An additional query was used to allow the definition of technical debt from an AsciiDoctor table in doc/architecture/05_building_block_view.adoc (cf. jQA add known technical debt, just remove the comment at the beginning of the line to make the test pass).
link:jqassistant/structure.adoc[role=include]
link:doc/architecture/05_building_block_view.adoc[role=include]
In jqassistant/structure.adoc the last rule was defined with role=constraint
(jQA define layering as constraint). If the query returns a non-empty result it is considered a problem. Since
it is tagged as severity=critical
it finally breaks the build.
link:jqassistant/structure.adoc[role=include]
Software architectures often require that certain classes belong to particular packages, e.g.,
-
DAO
(Data Access Object) classes should be part of the.dao
package hierarchy, or -
Entity classes (defined by the JPA
@Entity
annotation) should be defined in.domain
packages.
AU provides several checks for the persistence component in src/test/java/com/tngtech/archunit/exampletest/DaoRulesTest.java.
dao
packagelink:src/test/java/com/tngtech/archunit/exampletest/DaoRulesTest.java[role=include]
@Entity
annotated classes reside in a domain
packagelink:src/test/java/com/tngtech/archunit/exampletest/DaoRulesTest.java[role=include]
The corresponding tests for jQA are implemented in jqassistant/daorules.adoc.