leanmind logo leanmind text logo

Posts

Why you should use ArchUnit

Once upon a time, there was a legacy project. One can see the right architectural design patterns shaped into the application’s modules. The domain held the correct logic. The interaction with the database and system inputs were appropriately encapsulated.

However, once you start digging into the code, several features spread the logic across all layers: There were database entities in the Controllers, Transactions everywhere, incorrect use of the ORM with hardcoded SQL, cyclic dependencies, etc.

As you can imagine, bug fixing became a nightmare. The development of new features took ridiculous amounts of time. New developers Onboarding was tedious and time-consuming.

The reason

In my experience, this can be the result of several factors among which we can list:

The solution

We are knights of the code, how can we programmatically avoid this? The answer is ArchUnit.

ArchUnit is a Java library to check the architecture of your Java code using plain Java UnitTests. Using a simple syntax, we can ensure the code quality persists. Changes conflicting with architectural principles will break the build hence they will be identified early in the development process.

Enough talking, let’s see some examples:

Keep the classes where it should

1
2
3
4
5
6
@ArchTest
public static ArchRule entities_should_be_placed_in_entity_package =
    classes()
        .that().areAnnotatedWith(Entity.class)
        .or().haveSimpleNameEndingWith("Entity")
        .should().resideInAPackage("..database.entity..");

As you can see in this example, we can identify an entity by its name or annotation. Now we can assert they reside in the right package. Note the two dots .. are a wildcard for any value, so the following examples are valid:

com.mycompany.book.infrastructure.database.entity.BookEntity
com.mycompany.author.infrastructure.database.entity.AuthorEntity

But this examples will fail:

com.mycompany.book.domain.entity.BookEntity
com.mycompany.author.infrastructure.controller.entity.AuthorEntity

Comply naming agreements

In the following example, we can ensure every class in the controller package and annotated with RestController, have the right suffix.

1
2
3
4
5
6
@ArchTest
public static ArchRule controllers_should_comply_naming_convention =
    classes()
        .that().resideInAPackage("..controller..")
        .and().areAnnotatedWith(RestController.class)
        .should().haveSimpleNameEndingWith("Controller")

Stacking preconditions

In the above examples, you can note the predicates are connecting with different logic operators (and/or). This functionality allows you to have more specific or flexible rules as needed.

Conclusion

Well defined software architecture is crucial to your project. It can ensure you to maintain, evolve and extend your codebase.

Using ArchUnit you can test the code standards of your application and any violation will quickly break the build. The developer can notice the mistake at an early stage and fix it before even committing the change.

In this article, we wanted to illustrate simple yet powerful examples to programmatically ensure code standards are met.

Do you want to know more? Drop a comment and we will create a second post with further examples.

Published on 04/01/2021 by Leanminder Anonymous

Do you want more? We invite you to subscribe to our newsletter to get the most relevan articles.

If you enjoy reading our blog, could you imagine how much fun it would be to work with us? let's do it!

We promote the professional growth of your dev team