Giter VIP home page Giter VIP logo

spring-modulith's Introduction

Spring Modulith Revved up by Develocity

Spring Modulith allows developers to build well-structured Spring Boot applications and guides developers in finding and working with application modules driven by the domain. It supports the verification of such modular arrangements, integration testing individual modules, observing the application’s behavior on the module level and creating documentation snippets based on the arrangement created.

Quickstart

  1. Create a Spring Boot application on https://start.spring.io

  2. Add Spring Modulith to your application by adding this to your pom.xml:

    <!-- The Maven repository to pull the dependencies from -->
    <repositories>
      <repository>
        <id>spring-snapshots</id>
        <url>https://repo.spring.io/snapshot</url>
      </repository>
    </repositories>
    
    <!-- Include the BOM for simplified version management -->
    <dependencyManagement>
      <dependencies>
        <dependency>
          <groupId>org.springframework.modulith</groupId>
          <artifactId>spring-modulith-bom</artifactId>
          <version>1.0.0-SNAPSHOT</version>
          <scope>import</scope>
          <type>pom</type>
        </dependency>
      </dependencies>
    </dependencyManagement>
    
    <dependencies>
    
      <!-- The test dependency to pull in verification APIs -->
    
      <dependency>
        <groupId>org.springframework.modulith</groupId>
        <artifactId>spring-modulith-starter-test</artifactId>
        <scope>test</scope>
      </dependency>
    
    </dependencies>
  3. Create a Java package arrangement that puts business modules as direct sub-packages of the application’s main package.

    □ Example
    └─ □ src/main/java
       ├─ □ example           <1>
       |  └─ Application.java
       ├─ □ example.inventory <2>
       |  └─ …
       └─ □ example.order     <2>
          └─ …
    1. The application root package

    2. Application module packages

  4. Create an ApplicationModules model, run verifications and create documentation snippets.

    class ApplicationTests {
    
      @Test
      void writeDocumentationSnippets() {
    
        var modules = ApplicationModules.of(Application.class).verify(); (1)
    
        new Documenter(modules) (2)
          .writeModulesAsPlantUml()
          .writeIndividualModulesAsPlantUml();
      }
    }
    1. Creates application module model and verifies its structure.

    2. Renders Asciidoctor snippets (component diagrams, application module canvas) to target/modulith-docs.

  5. Run integration tests for individual application modules.

    □ Example
    └─ □ src/test/java
       └─ □ example.order
          └─ OrderModuleIntegrationTests.java
    @ApplicationModuleTests
    class OrderModuleIntegrationTests {
    
      @Test
      void someTestMethod() { … }
    }

Reference documentation

Find the reference documentation here.

Contributing

Pull requests are welcome. Note, that we expect everyone to follow the code of conduct.

License

Spring Modulith is Open Source software released under the Apache 2.0 license.

spring-modulith's People

Contributors

benjaminknauer avatar erichaagdev avatar jaeggir avatar jochenwierum avatar josroseboom avatar jwalter avatar khmarbaise avatar ksilz avatar lilbaek avatar lukasdo avatar maciejwalkowiak avatar meistermeier avatar mouaadaassou avatar mweirauch avatar nikimicallef avatar nkolosnjaji avatar odrotbohm avatar rwinch avatar scordio avatar simonverhoeven avatar taoaozw avatar thombergs avatar tobhai avatar yossisp avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

spring-modulith's Issues

Drop fallback, in-memory implementation of the `EventPublicationRepository`

We currently ship an in-memory implementation of EventPublicationRepository and use this as a fallback in case the user has not decided for a persistent repository implementation. That's actually doing more harm than good as the in-memory implementation is not transactional in the first place, which means that event publication registry entries would be written, even for a transaction rollback.

We should drop the in-memory implementation entirely and nudge users to select a persistent implementation (which we already do with the starter POMs available).

Fix order of `JpaEventPublicationAutoConfiguration` to run before the general JPA auto-configuration

Unless explicitly defined, auto-configuration types are ordered by name. This caused the JpaEventPublicationAutoConfiguration in the Moduliths project to run before the HibernateJpaAutoConfiguration as the former's package was org.moduliths.…. After the package rename to org.springframework.modulith.…, the order has been inverted and thus causes the entity scanning to be set up before JEPAC can add the additional package.

We need to explicitly order JEPAC before HJAC to make sure, the package gets added before the JPA initialization happens.

Avoid `IOException` in public `Documenter` API

There's hardly anything you'd reasonably do with an IOException being thrown from the API of Documenter as they'd all indicate a fundamental problem with the file system and Documenter is really primarily used from test cases.

Improve consistency in `Documenter` API

  • Consistently add overrides that assume customization option defaults without requiring explicit parameters.
  • Rename Options to DiagramOptions for consistency with CanvasOptions.

Verification that no classes exist outside Application‘s package

Hi,

in ArchUnit, there is the possibility to check that there are no classes outside of the packages, for which an architecture is defined.
Wouldn’t this be a nice additional verification for spring-modulith too ?
It would ensure, that there is no other root package besides the application‘s main package.

Maybe this is a non-issue, if all root packages are verified by modulith anyway (?)

So I have some questions to be clear about modulith's conecepts:

1) what are valid root packages ?

└─ □ src/main/java
   ├─ □ com.mycompany
   |  └─ Application.java
   ├─ □ com.mycompany.inventory 
   |  └─ …
   └─ □ com.mycompany.order  
      └─ …

Is "com.mycompany" considered a root package ? Or would that just be "com" ?

2) many root packages ? all packages considered by modulith ?

└─ □ src/main/java
   ├─ □ example1
   |  └─ Application.java
   ├─ □ example1.inventory 
   |  └─ …
   └─ □ example1.order  
      └─ …
   ├─ □ example2
   |  └─ MySneakyServices.java

Is "example2" also regarded as a second root package by modulith and is it allowed to access anything public from example 2 ?

These are my findings, when I experimented with the provided example:
"com.mycompany"

image

...and this also fails to verify dependencies when renaming "com.mycompany" to "example2"

So, my wish would be:

  1. to have the optional 'strict' mode, in which all packages are considered, not just the one where "Application" (main) resides in

  2. to optionally be able to specify root packages like "com.mycompany", so that it is made explicit, and that there is no convention of just considering the first package path "com"

Investigate support for build time optimization

Context

A common challenge for modulithic applications is that a change in the version control system triggers a build of the overall system. That build usually consists of steps that are executed for the entire system, which means: for all modules, whether the change in question actually affects a module directly or transitively.

The structural information we have about the system could be combined with knowledge about the change set at hand to identify which modules are directly affected by the change itself. We could then find out about all modules directly or transitively depending on the "dirty" modules and limit the test execution to filter test cases contained in those modules only. Similarly to limiting the parts of the application that are actually bootstrapped during module-specific test via @ApplicationModuleTest.

Ideas

JUnit 5 has dedicated support to hook into the test discovery process, i.e. it should be possible to place a JAR in the classpath of e.g. the Maven Surefire execution that filters the test cases to actually be executed.

We also need to find a mechanism to identify, what the set of changes is, we want to start from. During local development, this is likely to be the files currently considered changed by Git. During a CI run (the more important aspect) it's likely the last change set or the set of change sets in between the previous build and the current one.

Original ticket:

Make sure test autoconfiguration is ordered first

We should declare ModuleTestAutoConfiguration as @AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE) to make sure that other autoconfiguration classes that use AutoConfigurationPackages already see the tweaked arrangement.

`EvenPublication` lookup might fail if domain events are not entirely unique

Currently, we do not imply any constraints on the domain events to get publications registered for. This results in the potential case of an event published twice and us creating publications for the same event representation and publication target identifier (PTI). The lookup of an event publication to mark it completed currently assumes to find a unique entry per event and PTI, which we cannot actually rely on.

As a mitigating measure, it makes sense to at least let the lookup filter for uncompleted events so that we would at least select an uncompleted publication to eventually be marked as completed. As there's still a chance that even in the case of multiple publications for the same logical event, concurrent readers might lookup the same database row and leave one publication incomplete, we need to highly recommend to use unique event instances.

Better dependency verification with named interfaces

It would be nice if the explicit definition of allowed dependencies (via @Module) allowed to refer to named interfaces via moduleName :: namedInterfaceName and reference to exposed type that reside in other named interfaces of the module would be rejected.

Modulith in multi-module projects

What could be the relationship with a maven multi module project?

I normally divide big projects in several modules (mainly by functional packages) and clearly describe the dependencies between them in the pom.xml, avoiding some strange dependency cycles and other problems in long run developments.

Evaluate automatic purge mechanisms for completed events

  • Archive table – instead of marking an event as completed in the "current table" we could write an archive table to contain older, completed events and the original one just get completed events wiped (two options in turn: archive on insert, archive on completion)
  • Indexes (on event and publication target identifier)
  • Sliding window (based on time, number of completed publications)

Module Canvas driven by component aspect of a module

The current structure of the Module Canvas is driven be the stereotypes expressed in the module. It would be nice if we could expose the component aspect a bit more by structuring it around the following 3 segments:

  1. Provided – all exposed (public) APIs (components, services) and published events
  2. Required – all consumed external dependencies (components, services) and consumed events
  3. Internal – all non-public components and events.

Port of moduliths/moduliths#195.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.