Kontakt
stefan.bente[at]th-koeln.de
+49 2261 8196 6367
Discord Server
Prof. Bente Personal Zoom
Adresse
Steinmüllerallee 4
51643 Gummersbach
Gebäude LC4
Raum 1708 (Wegbeschreibung)
Sprechstunde nach Vereinbarung
Terminanfrage: calendly.com Wenn Sie dieses Tool nicht nutzen wollen, schicken Sie eine Mail und ich weise Ihnen einen Termin zu.

Getting Started with Spring Modulith

Spring Modulith is a framework for modular monoliths. It is a somewhat “puristic” approach to implementing a DDD specification (based on aggregates and their domain events) into code. The framework is designed to make the DDD building blocks explicit in the code. On the downside, the framework is relatively new, very strict in its conventions, and not always that well documented. Therefore, this infopage will help you getting started with Spring Modulith.

Related video(s)

What is Spring Modulith?

What is a Modulith?

Modulith is an artificial word formed from “monolith” and “module”. A monolith is an application that is deployed as a single unit. This is in contrast to microservices, where each service is deployed independently. A monolith is much easier to develop and deploy as greenfield project. This is why, at the peak of the microservices hype, Martin Fowler suggested to start with a monolith and only later, when the system has grown, to split it into microservices (if this is beneficial due to the organization’s size and complexity).

This, of course, does not mean to fall back behind the learnings from Domain Driven Design (DDD) that a domain needs to be properly understood, modelled into bounded contexts, and implemented structured into strictly decoupled aggregates with their domain events. This is the “modular” part of the word “Modulith”. The earliest source using this team (that I know of) is Herbert Dowalil’s article Modulith First! Der angemessene Weg zu Microservices in 2019 (if you know of an earlier source, please let me know.) Carola Lilienthal’s JAX blog from 2020 Von Monolithen über modulare Architekturen zu Microservices mit DDD is also still a good read on the topic. Both articles are in German, but you can use auto-translate.

And what is Spring Modulith? And why are we using it?

Spring Modulith is the brainchild of Oliver Drotbohm, one of the masterminds behind the Spring framework. Its goal is to provide a framework for such “modular monoliths” where the DDD principles are strictly adhered to, and are made explicit in the code.

I am not sure if it is fair to call Spring Modulith “experimental”, but it is certainly “early days”, and not as widely used as the Spring framework in general. (Actually, I am not aware of testimonial for production use anywhere). The documentation is not very extensive, there are very few complex (and therefore useful) code examples, and not really any easy-to-use tutorials. This infopage is an attempt to fill this gap, at least to some extent.

On the other hand, it seems to be robust and well thought out. This is the reason why I have chosen it for the Domain Driven Design Master course - it is a good way to make the DDD specification explicit in the code. Since we don’t really have to carry it through to production, we don’t need to discuss if it is “production ready” or not. (Although I am still making up my mind about this.)

What makes Spring Modulith different from “normal” Spring Boot applications?

DDD building blocks explicit in the code

The first major difference is that Spring Modulith is designed to make the DDD building blocks explicit in the code. It uses the jMolecules library to explicitly mark aggregates, identifiers, and other core concepts of DDD. This is a good thing, as it makes the code more readable and understandable. (On the downside, the tool support for jMolecules in IDEs like IntelliJ is somewhat cumbersome, compared to well established libraries like e.g. Lombok. See more about this below.)

Enforcing Vernon’s Aggregate Design Rules

The other major difference is that Spring Modulith is strictly enforcing Vaughn Vernon’s “aggregate design rules”. Meaning: Aggregate boundaries are transaction boundaries, aggregates are small, aggregates references are by identifier only, and they communicate through domain events.

No cyclic dependencies

The third major difference is that Spring Modulith must not have any cyclic dependencies - not even in subscribing to domain events. This is a major difference to “normal” Spring Boot applications, where cyclic dependencies are not prevented by the framework “out of the box”.

How to understand the Basics

Understanding the DDD core concepts

The first thing you should do is to watch the ArchiLab videos on DDD core concepts listed on top of the page. They should give you a good understanding of some of the core basic concepts of DDD. (The videos are in German, but have manually curated English subtitles.)

In addition, there are several DDD info pages that should help you with a better understanding of the basic concepts:

Understanding Spring Modulith

The best entry point to get an understanding what Oliver Drotbohm wants to achieve with Spring Modulith is (IMHO) his interview by Eberhard Wolff in Wolff’s “Software Architecture TV” Youtube series. This is in German, but you can use auto-translate - you should catch the main points.

Setting up your IDE (using IDEA IntelliJ)

JMolecules support in IntelliJ

There is a helpful jMolecules plugin, which you can install in IntelliJ. It shows the jMolecules annotations in the structure view of the IDE. In addition, it renders a dedicated (virtual) jMolecules node in project view for all stereotyped types, showing instances of aggregates, entities, value objects, and identifiers.

jmolecules-plugin.png

Add “Before Launch” tasks for the ByteBuddy plugin

Spring Modulith uses its own implementation of annotations and types to specify aggregates, entities, and repositories. They are not compatible with the regular Spring Boot annotations. Therefore, if you use a Spring Modulith @AggregateRoot or @Service annotation, or derive your aggregate root class from org.jmolecules.ddd.types.AggregateRoot, then some information necessary for Spring Boot to recognize entities or services are missing.

Spring Modulith uses the ByteBuddy library to generate the missing information. Adding this in the pom.xml is not sufficient for development with IntelliJ, as IntelliJ uses an own internal build system, and doesn’t use Maven for building the project. If you just run the application from IntelliJ, or run the tests, it would fail with a runtime error, since the services and entities are not recognized by Spring Boot.

A solution to fix this is to add a “Before Launch” task in IntelliJ that runs the ByteBuddy plugin. This is a bit cumbersome, but it works. The problem and the approach are described in this IDEA issue, as a dialog between Oliver Drotbohm and the IntelliJ developers. This is what your run configuration should look like after you have added the “Before Launch” task.

before-launch-annotated.png

Here is how you can set up the “Before Launch” task in IntelliJ:

  1. Go to “Run” -> “Edit Configurations…”
  2. Pick the run configuration you want to modify (e.g. for all tests)
  3. Enable the checkmark on “Add before launch task”.
  4. Click on the “+” sign and add a “Run Maven Goal”
  5. Enter the goal “clean:clean” and click “OK”
  6. Add a plain “Build” task (this is necessary to have the compiled binaries available, which will then be processed by the ByteBuddy plugin)
  7. Add a “Run Maven Goal” task with the goal “byte-buddy:transform-extended” and click “OK”
  8. Remove the first build task, which had been added by default (it seems there is no way to reorder the tasks)

Now you can work on your Spring Modulith repository in IntelliJ, and run the tests or the application.

Get the “inofficial Spring Modulith example applications”

In my experience, you’ll be lost in the nitty-gritty details and pitfalls of Spring Modulith without a good application example, which is complex enough to help you. (This will be especially true if you come from a long Spring Boot background, like me.) There are two repositories that are not obvious to find, but which I found very helpful.

Oliver Drotbohm’s “Tactical DDD Workshop” repository

The repo that Drotbohm mentions in the aforementioned video interview with Eberhard Wolff is quite helpful for understanding the basics. You find it at https://github.com/odrotbohm/tactical-ddd-workshop.

The “Amundsen” repository

The Amundsen project is the result of Master Thesis conducted at ArchiLab by Marco Reitano (in German). Its goal was to explore the potential of Spring Modulith in a real-world project, with regard to the potential dilemmas und pitfalls in complex domains. The domain used in this thesis is a simplified version of the Microservice Dungeon project that has been developed at ArchiLab.

The original Microservice Dungeon consists of several microservices (see repositories at https://gitlab.com/the-microservice-dungeon/). The Amundsen project is a prototypical Modulith version of it. The tests are fully functional, so you can use this repository as a comparison and reference for your own Spring Modulith project.

The repo can be found at https://github.com/MarcoReitano/amundsen.

Further Reading

In addition to the information provided above, the official Spring Modulith documentation will probably be useful (although in its usual bone-dry fashion). Other resources that I often find quite helpful, like e.g. the numerous Baeldung articles on Spring topics, completely underwhelmed me since they don’t even come close to the level of complexity needed to bring Spring Modulith to a productive level.

This is a subjective list of resources I found helpful:

  • Working with Application Events - surprise: it’s a bit different then working with default Spring eventing, since by default your domain events are asynchronous. This changes a lot of aspects in your working with control flow and transactions.
  • As a consequence, integration testing of Spring Modulith applications requires quite a different approach than the “usual synchronous call testing”. (Here, the Amundsen repository is a good reference.)
  • If you interested in the way Spring Modulith applications can be checked for their “conceptual consistency”, have a look at the ArchUnit-based standard tests. I found them surprisingly easy to use, given that ArchUnit is a very powerful but poorly documented tool.

Please let me know if you have found other helpful resources, or if you have any other feedback on this infopage. This is work in progress, and I will continue to update it.