spring-projects / spring-modulith

Modular applications with Spring Boot
https://spring.io/projects/spring-modulith
Apache License 2.0
813 stars 140 forks source link

Improve module detection by type #299

Open thomascaillier opened 1 year ago

thomascaillier commented 1 year ago

Use case

In order to expose the types of a module and all of its sub packages, I'm implementing my own ApplicationModuleDetectionStrategy as described in the documentation, as well i can have module base packages as following :

Expected behaviour

org.myapp.a.b is a module, so org.myapp.d can depend on org.myapp.a.b.SomeService

What's happening

My modularity test based on ApplicationModules.of(org.myapp.MyApplication.class).verify() fails because module org.myapp.d depends on non-exposed type org.myapp.a.b.SomeService

In-depth analysis

Diving in how the ApplicationModules:detectViolations method works, I found that ApplicationModules:getModulesByType was the origin of my problem:

return modules.values().stream()
    .filter(it -> it.contains(type))
    .findFirst();

In my case, multiples modules contains my type org.myapp.a.b.SomeService (org.myapp.a and org.myapp.a.b), but only the first one is taken. Then, because org.myapp.a.b.SomeService isn't exposed by the first module org.myapp.a, a violation is detected.

Suggestion

Improve this ApplicationModules:getModulesByType in order to take the finest/deepest module for a type, which would be in my case org.myapp.a.b

odrotbohm commented 1 year ago

That's an interesting case. Am I right in assuming that you do not consider a.b a submodule of a? If so, why is a even a module in the first place?

We currently do not really support nested modules(, yet), and your suggested solution would establish an arrangement, in which nested modules are automatically exposed to other modules. While apparently that's what you expect in this case, but I wonder how common the same source code arrangement is and the nesting is supposed to be used to control that a.c only uses particular types of a.b but still hide both of them from d?