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.
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.
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.)
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.)
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.
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”.
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:
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.
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.
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.
Here is how you can set up the “Before Launch” task in IntelliJ:
Now you can work on your Spring Modulith repository in IntelliJ, and run the tests or the application.
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.
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 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.
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:
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.