Great video, exactly how I handled separated modules in my modular monolith
@MilanJovanovicTech10 күн бұрын
Nice!
@MilanJovanovicTech10 күн бұрын
Want to master Clean Architecture? Go here: bit.ly/3PupkOJ Want to unlock Modular Monoliths? Go here: bit.ly/3SXlzSt Get the source code here: www.patreon.com/milanjovanovic
@PippiTheLongSock9 күн бұрын
I feel like with the current implementation, where you call the IOrderService in the shipping consumer, you are introducing a degree of coupling which can potentially cause problems when (if) you decide the extract any of the two modules into a separate application (process). In that case, you will need to implement some sort of blocking out of process communication and this would mean that the shipping module (microservice) will always require the orders to be up and running. Of course, this might be a balanced well worth tradeoff, but still it is good to keep the potential pitfalls in mind. You can also continue evolving the current demo project in future videos by removing the direct call to the orders module. Anyway, just my 2 cents, great video as always, though!
@MilanJovanovicTech9 күн бұрын
It's a good remark. Let me do exactly that in the next video and discuss the tradeoffs!
@baranacikgoz9 күн бұрын
I prefer using Masstransit Request Response pattern (which I saw it thanks to you) for this. Introducing a shared service interface defeat the purpose of decoupling imo. As always, thanks for the video
@MilanJovanovicTech9 күн бұрын
It's good to have options!
@chanep17 күн бұрын
Nice replacement of multi assemblies with Architecture.Tests
@MilanJovanovicTech7 күн бұрын
Yes, it's an interesting alternative. I haven't explored all the possible options
@mreshboboyev10 күн бұрын
This video is great, thank you! Can you show this in a diagram, using shapes?
@MilanJovanovicTech10 күн бұрын
Check this out: www.milanjovanovic.tech/blog/internal-vs-public-apis-in-modular-monoliths
@jackpioneer356610 күн бұрын
Great video as always! I noticed that in your recent videos, you are using the DbContext directly without the repository and unit-of-work patterns. Is this for simplicity, or do you think these are unnecessary abstractions?
@vinydanylo10 күн бұрын
The DbContext already implements the unit of work pattern (SaveChangesAsync method) and the repository pattern (DbSet properties)
@MilanJovanovicTech10 күн бұрын
Both, kind of
@moeelhariri804110 күн бұрын
Hey Milan, did you intentionally suffix IOrderService with “Service”? Do you think IOrderShippingInfoQuery would be a more explicit name, or would you reserve “Query” and ”Command” suffixes for endpoint request contract types only, representing entry points into the system?
10 күн бұрын
imo, it´s way more convenient to expose the module public api as a facade than multiple separate querys/commands)
@MilanJovanovicTech10 күн бұрын
Either is fine, I just didn't want to go so granular with specific names
@fredik277 күн бұрын
Hey Milan, when i try to write my modularity test, i get: 'Program' is inaccessible due to its protection level when i try to load the program assembly: private static readonly Architecture Architecture = new ArchLoader() .LoadAssemblies(typeof(Program).Assembly) .Build(); Visual studio keeps suggesting that i use 'using Microsoft.VisualStudio.TestPlatform.TestHost;' but that seems strange to me. I really cant see what i am doing differently?
@MilanJovanovicTech7 күн бұрын
Make a partial class
@mastersiper9 күн бұрын
Can you please make a video about modular monoliths with an message based API layer.
@MilanJovanovicTech9 күн бұрын
Yes
@mastersiper9 күн бұрын
@ I'm looking forward to it!
@thedacian1239 күн бұрын
Woukd have not been a good architecture that the modules communicate via SB using MediatorR or channels?
@MilanJovanovicTech8 күн бұрын
Same level of coupling, technically
@mahmudsulemansheikhwunnam358010 күн бұрын
Please what drives this kind of structure. As a person who just started using .net my first thought would have been to use areas for each module/component.
@MilanJovanovicTech10 күн бұрын
There are many reasons, but it mostly depends on the complexity and scalability of your application. Check out this: www.milanjovanovic.tech/blog/internal-vs-public-apis-in-modular-monoliths
@iliyan-kulishev10 күн бұрын
How I do it, given the fact that I do CQRS, is to have every module in different assembly. But they don't refer to each other via interface, just via public service classes. And the commands, queries and responses are public and used in the services classes for input and output. I see no value of "hiding" the fact that I'm doing CQRS in every module. What do you think about this ?
@MilanJovanovicTech10 күн бұрын
You're not really hiding the fact within the module - you'd be hiding it from other modules.
@iliyan-kulishev10 күн бұрын
@MilanJovanovicTech And I am not doing that. Why is that wrong in your opinion ?
@MilanJovanovicTech9 күн бұрын
@ I was just referring to public-internal and what's visible to others. If other modules can see public members (commands/queries) of your module, what prevents them from using it?
@iliyan-kulishev9 күн бұрын
@@MilanJovanovicTech Nothing prevents them. If they use the mediator directly with them, I wouldn't mind either. The handlers are internal though. I like having the commands/queries public, so there's no double work with typing parameter lists in the public services. Another reason is that any client can decorate the handlers of their choice - all or for particular command/query. My weird way :)
@vincentcifello44357 күн бұрын
This misses the forest for the trees. All you have done is sweep the coupling under the rug. The real coupling here is the fact that the OrderService is storing and managing the shipping address. This forces the “Shipping Service”, whatever that is, to depend on the Order Service to do its job. Everything else is just indirection to hide this problem. There is simply no reason whatsoever that the shipping address can’t be stored and managed by its proper owner- the Shipping Service.
@MilanJovanovicTech7 күн бұрын
Data ownership is a separate topic here (to be discussed). The communication here could've been async also, ending up with a copy of the shipping address in the shipping module. Recall that we're dealing with a monolith in this example, not separate services.