Replies: 5 comments 2 replies
-
FWIW, I've realised/discovered that it's possible to turn off the DAG module verification, so that's where I'm at now. https://docs.spring.io/spring-modulith/reference/2.0/verification.html#_customizing_the_verifcation |
Beta Was this translation helpful? Give feedback.
-
@odrotbohm As discussed above, I want to turn off the test for cyclic dependencies - how can I do this? The documentation suggests this is possible but doesn't go into detail or provide an example. This might be a useful addition to the documentation. |
Beta Was this translation helpful? Give feedback.
-
That's quite a lot to digest, but here are a few things that are at least at odds with a modular arrangement:
In a practical example, an order would be assigned to a customer by keeping an ID. All Orders for a particular customer would not be modeled as a collection in Customer, but rather as a query on the Regarding the “drinks by orders” example, I'd argue that's a statistics requirement that would be tracked in a separate module. On the other hand, the drinks module could listen to an event interface ( |
Beta Was this translation helpful? Give feedback.
-
Hi @odrotbohm , I've decided it's best to deactivate the cyclic modules check and all I really need right now are some simple instructions on how to do that. I'm happy to explain my reasoning another time... |
Beta Was this translation helpful? Give feedback.
-
Hi @odrotbohm , Welcome back from your conference tour :-) I enjoyed hearing your latest thoughts on moduliths etc via the YouTube Devoxx recordings. In the spirit of your remark that "you never learn anything from someone you agree with", here's my attempt to disagree with you on the requirement for no cyclic dependencies between modules. This issue remains an important one for me and I think it would be interesting to explain my own point of view and, certainly, to hear your response. Let's suppose that we have a simple spring modulith project with two modules, M1 and M2, and let's suppose our database is a standard relational/SQL database. Suppose M1 defines some entity So, we have two modules, M1 and M2. M2 is the root of the dependency graph (it has no dependency on any other module) while M2 depends on M1. Finally, let's assume that we have REST API endpoints provided by M1 and M2 which allow read/write access to these entities. So M1 provides something like I think that's all the setup I need, so onto my questions... Entity A and entity B are represented in the database by two tables, call them The problem I have is how to achieve this with Spring Modulith. Away from Spring Modulith (if we were thinking of So, how is one supposed to achieve this sort of thing in Spring Modulith if there can never be bidirectional dependencies between modules? In fact, we should split the question in two. How (if at all) can you do this sort of thing in Spring Modulith? And, assuming there is some way to do it, is it worth doing it this way rather than simply relaxing the restriction on bidirectional module dependencies? I mostly want to hand over to you now to hear how you would handle this, but here are some possibilities I've considered myself.
Thanks for working through this. I hope I've made the case that it's an important question and perhaps you're able to see some simpler solutions. Ultimately, I think this sort of "downwards" querying is going to be absolutely ubiquitous in any non-toy application, and I think it does genuinely put pressure on the idea that bidirectional dependencies should be made impossible. I'm supportive of the idea that bidirectional dependencies should perhaps be minimized, but that's not because I think bidirectional dependencies are intrinsically bad (see next paragraph...), it's because I think all dependencies should be minimized. I'm also supportive of the idea that it's helpful to be able to keep track of bidirectional dependencies, but again, that's not because bidirectional dependencies are instrinsically bad, it's because it's useful to keep track of all intermodule dependencies. And remember, we are already working in a "modular" arrangement in the sense that modules can only depend on other modules' exposed APIs, and that applies to bidirectional dependencies, too. So, I just don't find that there's any reason to make bidirectional dependencies impossible. If you could always easily replace transform a system with bidirectional dependencies into a DAG, then maybe that would be worthwhile, but my own conclusion, based on the example above, is that this simply isn't possible. So, my vote is that Spring Modulith should not absolutely enforce a restriction on bidirectional dependencies. Perhaps, for example, Modulith could be configured with three levels of bidirectional checking - There is perhaps a deeper philosophical argument to be made, too. A bidirectional dependency is not different in kind from a uni-directional dependency. Wherever you have a bidirectional dependency, it is really just two one-way dependencies, and we already accept that one-way dependencies are fine and often essential. Elsewhere I think you have written that enforcing a DAG is the "key to an evolvable architecture", but I don't ultimately think that's true. I think enforcing the boundary between a module's exposed APIs and its internals is good and helpful. I think allowing modules to communicate via events is good and helpful. And I think having a system like Spring modulith which can show you the dependencies for a particular module is good and helpful - it's helpful, for example, because if I want to make a change in one module, it's helpful to know what other modules that might affect. But I can accept all of that without thinking that a ban on bidirectional dependencies is always good and helpful. (I suppose someone might argue that if you allow bidirectional module dependencies, then there will be "circles" in the dependency graph and so the number of modules that might be affected by a change is potentially infinite, but that's incorrect. All Spring Modulith applications will have a finite number of modules, so the number of modules affected by a change will also be finite.) So, ultimately, I think the ban on bidirectional dependencies is unmotivated - it's a solution that's looking for a (non-existent) problem. If all the above isn't enough to convince you, perhaps it worth adding simply that representing dependencies in one's domain can have business value and if there is an important bidirectional dependency in the world that your business works in, why wouldn't you want to be able to represent it? Thanks for reading and I look forward to hearing your response. |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
-
Suppose you have a modulithic app with two modules, A and B. Module B depends on module A but not vice versa; so A is the root of the dependency graph. I'm imagining that this app provides a REST API, though I think an html web app would work just as well for this discussion. And I'm imagining that this app uses Spring Data JPA for persistence.
Suppose module A defines an entity
Aardvark
and module B defines an entityBall
, which is always owned by someAardvark
i.e. there's a many-to-one relationship. To make this work, module B imports theAardvark
entity from module A.Now suppose you have a REST endpoint at
/aardvarks
which is defined by module A and which returns a list ofAardvarks
. And suppose you want to be able to filter this list based on whether anAardvark
owns aBall
or not.At the moment, the only sensible way I can think to achieve this is to have a query in module A that somehow references the
Ball
entity in module B. But... that means that module A has some sort of dependency on module B, after all. So, is this considered acceptable within the spirit of Spring Modulith, or is there some other way to achieve what I want that I haven't spotted yet?My question above is whether this sort of thing can be handled within the spirit of Spring Modulith. But a more immediate question is whether Spring Modulith would actually allow it i.e. would it raise an error in this sort of case? In my real situation, I've so far been writing my downstream query as a native query, which corresponds to a situation where module A in my example has a SQL dependency on module B's data, but module A's code does not depend on module B's code. I haven't tested this, but I imagine Spring Modulith wouldn't test for a SQL dependency and so wouldn't raise an error. But I guess the situation would be different if I used either Spring Data JPA's repository queries or wrote my query in JPQL. Then, it seems, module A's code would depend on module B's code because e.g. the query code in module A would depend on the hibernate classes in module B. So there would in fact be a circular code dependency between A and B (given that ex hypothesi B's code depends on A's code). Perhaps Modulith would raise an error in this case; but I haven't tested it. It also seems that using an
@ApplicationModuleTest
in module A would require loading module B, since A's code depends on B's code (assuming that tests haven't already failed because of the circular dependency).I don't think one can get around this issue by creating an additional module C to integrate A and B because in order to integrate them both in C you would probably need to move almost all of A's and B's classes there. So, ultimately, the only answer seems to be that both module A's code and module B's code need to be located within the same module. And since these sorts of downward dependencies can in principle arise between any dependent modules at any time (i.e. at any time, it might become valuable to your business to be able to filter entities that appear earlier in the dependency chain by their relationship to entities that appear later in the dependency train), the ultimate impetus is to move most of your code into a single module, which tends to undermine the rationale for using Modulith in the first place. (I've been discussing a very simple example here, but to make things more concrete, consider the Spring RestBucks example application and imagine you have drinks and orders in separate modules, with orders downstream from drinks, but then it becomes useful to query drinks based on their number of orders...). Of course, there might still be some occasions where one is sure that one will never need to query an upstream entity based on its relationships with downstream entities - so there might be some occasions when one can safely split an app into a multi-module DAG. But I think the dominant pressure will be to move code into a single module.
I'd be grateful for other's thoughts on this, so please do share with me what you think. Ultimately, I think these sorts of downstream query dependencies are likely to arise in any non-toy example project, so I think it is important to know how to deal with them. I'm afraid I can't currently think of any feasible (or even non-feasible) way to handle them while continuing to use Spring Modulith. (In a previous discussion post I asked for help understanding the DAG requirement within Spring Modulith without wishing to criticise it. But I do think the issue I'm raising here is a serious problem.)
Beta Was this translation helpful? Give feedback.
All reactions