In the early 2000s, Service Oriented Architecture (SOA) popularized organizing code into distinct services mapped to business functions. It failed, however, to provide the necessary pragmatism for this lofty ideal.
A decade later, microservices offered pragmatism bordering on dogma: every service became its own repo and runtime process, spurring a new set of challenges intrinsic to highly distributed systems.
And now (thankfully!), Spring Modulith is here to offer a happy medium between the muddled monoliths of SOA and the overabundance of microservices. And—in contrast to the valiant but lackluster attempts of its predecessors—it provides the necessary framework to ensure that we get it right.
Enforcing Domain Driven Design
Spring Modulith provides an opinionated and fully implemented* set of rules to determine the architectural "correctness" of your code. It's opinions are based on Domain Driven Design (DDD), which focuses on crafting software to closely match the real-world domain.
Key Principles
Modular Organization: Each top-level package represents a functional module. Keep things tidy and focused.
Visibility Control: Expose only what's necessary. Elements for external use go in the module's base package; everything else belongs in sub-packages.
Event-Driven Communication: Foster clean communication between modules using Spring ApplicationEvents. Say goodbye to messy cross-module invocations.
Dependency Management: Cyclic dependencies are a no-go. Spring Modulith flags them, helping you maintain a healthy codebase.
How It Works
Integrating Spring Modulith into your Spring Boot application is a breeze. Just include the dependencies and run a quick check (from src/test/java...!):
ApplicationModules.of(Application.class).verify();This creates an in-memory representation of your code that is used to evaluate all of your modules (top-level packages) and any architecturally relevant elements within them, including Spring Beans, Services, Repositories, Event Listeners, Configuration Properties, Aggregate Roots, Events (published and consumed)...
Documentation and Testing
You can publish a visual snapshot of your architecture with UML or C4 diagrams, or generate a table-based overview called an Application Module Canvas (AMC).
You can also run integration tests on individual modules or subsets of modules to ensure a controlled and scalable codebase. This can help identify unintended dependencies on Beans from other modules and to be disciplines about mocking them.
Conclusion
This is the tip of the iceberg. The take-away is that if you're working with monoliths, Spring Modulith can help add some much needed structure and discipline into your code structure. If you're working with microservices, it gives you the choice to be more deliberate about the services that need to be coded, deployed and scaled independently, and to reduce code sprawl elsewhere.
Either way, Spring Modulith can teach us about good architectural practices and up our game in writing code that we can be proud of.