Want to master Clean Architecture? Go here: bit.ly/3PupkOJ Want to unlock Modular Monoliths? Go here: bit.ly/3SXlzSt
@developmentroselino2 ай бұрын
another day saved by milan, thank you so much for the lesson. its so much cleaner but im not separating by per project yet.
@MilanJovanovicTech2 ай бұрын
Happy to help! :)
@dotnetMasterCSharp2 ай бұрын
This is awesome and useful content thank you
@MilanJovanovicTech2 ай бұрын
Glad it was helpful!
@Districtgame7 ай бұрын
But doesn't that lead to distributed monolith antipattern? If you do it like this you are not able to use training module (in this case of course) without waiting for response of users module and that leads to question if these modules shouldn't be one. This is only easy example but in real world there will be a lot of references like this and if you need response from others modules to be able to finish your request there is maybe no point in separating these modules. Anyway, thank you for your videos they are awesome!
@EducateReality7 ай бұрын
yes, but I suggest you to get more in touch with the domain you are in and also the word „useage“ also a lot times used as „user“. I think your case is a useage case (where a user is useing a module). This useage is a specific module! I assume your next question, but don’t forget to set boundaries!
@MilanJovanovicTech7 ай бұрын
This does make sense. Which is why all decisions should be made in a given context. Keep in mind that the example in the video is contrived, to illustrate an idea/concept.
@lucasi-cs7 ай бұрын
Where would you put common classes that are used in all modules? For instance, a custom pagination class
@MilanJovanovicTech7 ай бұрын
Create a Common/Shared project that all modules can reference
@iagosoriano37347 ай бұрын
What would the dependency injection look like in the Training module? If the implementation of the UsersApi lives inside the Users.Infrastructure project, how would you inject it into the Training application, since the Training module only know the Users.Api project? Shouldn't only the interface to the Users public Api live in the Users module and its implementation in the common Infrastructure project?
@MilanJovanovicTech7 ай бұрын
DI takes care of it at runtime.
@iagosoriano37347 ай бұрын
@@MilanJovanovicTech In that case, you'd need a single DI container for all modules, and would have to avoid name conflicts among dependencies in different modules, right? I'm implementing a modular monolith in Node, and went with this one-container-per-module route.
@ahmedrizk1067 ай бұрын
what I do instead is to use Request/Response pattern provided by Mass Transit to avoid any coupling between the two modules, I have a contracts nuget package which is shared between all my modules/microservices, any module/microservices can simply request the data without any module knowing anything about where the response is coming from exactly. what do you think about this solution ?
@MilanJovanovicTech7 ай бұрын
They're still coupled by the nature of request-response, though. Just wrote about it: www.milanjovanovic.tech/blog/request-response-messaging-pattern-with-masstransit
@ChristopherBriddock7 ай бұрын
Milan, you should put out a code tip. To resolve your dependencies from the DI container rather than making an instance of the dependency inside a class. Like you have done in your CreateWorkoutCommandHandler. First you would need the IServiceProvider as a property with just a getter, amd initialized in the constructor, then you can use the GetRequiredService method to resolve dependencies from the DI container.
@MilanJovanovicTech7 ай бұрын
Sorry, which dependency is that? 🤔
@slvberg7 ай бұрын
Thanks for the video! Considering an alternative approach to the coupling: what if we add a Repository interface in the Training module's application to call the Users module API? This could simplify future efforts to split the Users module out of the monolith, without needing to touch the Training module's application logic. Plus, it would only require re-implementing the repository within the Training module, to fetch from the new Users module API, like REST. Just a thought to explore further.
@MilanJovanovicTech7 ай бұрын
That's like an Anti-Corruption Layer. I like the idea, for sure. We can even make it return an Athlete object, instead of a User. It's something I touched on in the MM course. Might cover it in the future videos in this series.
@petewarner10777 ай бұрын
Why implement IUserApi in the user module infrastructure project? If for example you were using a mediator pattern to dispatch requests to the user API, the handlers(implementations) for those requests naturally live at the application level, not the infrastructure level. We push implementations of non-deterministic code that produces side-effects (e.g IO operations) to the infrastructure, but an API is logically deterministic. Therefore I'd argue it should be implemented at the application level.
@MilanJovanovicTech7 ай бұрын
It makes more sense to me to implement this as part of Infrastructure, since it's an implementation of an abstraction. If it were a interface defined at the Application layer, where would you place the implementation?
@RobertoGarcia-w7y3 ай бұрын
@@MilanJovanovicTech The strategy is fine, is really semantic. Let's suppose that you've an interface called UserFetcher then on your infrastructure layer you'd have a HttpUserFetcher or a QueryBusUserFetcher or whatever doesn't matters, in the end it's what it's, an implementation detail on the infrastructure layer. Nice job, thanks for the video
@VintunaSayami7 ай бұрын
1. I didn't understood the concept of creating separate class library for same module. In User module, why do we need to create new class library for each section. Infrastructure, Domain, Api. Is it okey if we segregate it from folder only?? 2. You have created the shared Infrastructure which is again created in User module. what is the purpose of Shared Infrastructure??
@MilanJovanovicTech7 ай бұрын
1. It's just Clean Architecture. You can use anything. 2. Shared Infra is for cross-cutting stuff. Module Infra is for Users module only.
@mahmadmusffir84597 ай бұрын
Please create a tutorial on how to implement logging in SignalR for measuring and improving the performance of Hub methods.
@MilanJovanovicTech7 ай бұрын
Will consider
@sunzhang-d9v7 ай бұрын
Each module is given a different database, what if you need to federate the query, and the amount of data is very large
@MilanJovanovicTech7 ай бұрын
Merge the modules if the query is frequent. Or live with the added latency if it's not so frequent. We can also explore data duplication. Many options here
@ASIMKHAN-ig9eo7 ай бұрын
Can we do this with shadow properties?
@sunzhang-d9v7 ай бұрын
@@ASIMKHAN-ig9eo how to do it
@sunzhang-d9v7 ай бұрын
@@MilanJovanovicTech data duplication?
@ASIMKHAN-ig9eo7 ай бұрын
i am also curious to know as i also need some content on this as this is a problem
@stephendgreen15027 ай бұрын
They should have taught us all this decades ago. Well done.
@MilanJovanovicTech7 ай бұрын
I believe we were. What I want to know is how it became lost.
@stephendgreen15027 ай бұрын
@@MilanJovanovicTech Lack of proper engineering approach. Poor training in universities. Recruiters focussing on irrelevant skills. Immature developers being promoted and fast-tracked before they acquired proper understanding.
@nove13987 ай бұрын
Great gems here, a pretty debated topic online now.
@MilanJovanovicTech7 ай бұрын
As with any fad. Let's see how long it lasts.
@joga_bonito_aro7 ай бұрын
While I understand why some scenarios would require a modular monolith, I wouldn't go out of my way and create a module for every aggregate root entity. You would introduce one very big side effect, which would force you to track the distributed database consistency manually via manual atomicity handling/tracking. And doing such for every entity... just DON'T do it!
@MilanJovanovicTech7 ай бұрын
I agree. Maybe I should preface the videos with "this is a contrived" example?
@joga_bonito_aro7 ай бұрын
@@MilanJovanovicTech To me, the side effects seem like a no-brainer, but only after years of hurt, shitty programming and trial and error. Newcomers on the other hand wouldn't necessarily know the pros and cons right away. A preamble with pros and cons would suffice IMHO.
@MilanJovanovicTech7 ай бұрын
@@joga_bonito_aro That's a great point. As I'm planning a batch of videos right now. Keeping that in mind. Few slides at the start might be a good idea.
@joga_bonito_aro7 ай бұрын
@@MilanJovanovicTech Almost forgot. Great video as always Milan.
@TheScriptPunk7 ай бұрын
sir, lean into it. You know you want to... @satyayuga0 How about, a pattern where data is validated in, and falls into a pipeline. The pipeline is where the actual modularity takes place. The edge services can be distributed, or, confined within the same process. The consuming services shift their role from calling down to a direct reference of a handler, to a message bus (which is what you were doing before, except instead of explicitly typed parameters, you get to play with either grpc data, or json. I guess). Then, operate on the message bus. The requesting api customer will wait until all broad downstream effects bubble up, as you'd expect (expect your pieces probably have latent activity more than direct method calls) But, if you do this, you gain the benefit of not having to stick your service on 1 host process.
@icewolf19117 ай бұрын
Excellent video!
@MilanJovanovicTech7 ай бұрын
Ty!
@phw10097 ай бұрын
Such a nice approach, but copying Errors for user to Training module looks a bit smelly. I believe there is a better approach for that