Want to master Clean Architecture? Go here: bit.ly/3PupkOJ Want to unlock Modular Monoliths? Go here: bit.ly/3SXlzSt
@jensingels5958
10 ай бұрын
Thank you for the video. I would like to clarify the concept of CQRS (Command Query Responsibility Segregation) to address your points more clearly. CQRS is indeed about segregating the responsibilities of handling commands and queries, but it doesn't necessarily mandate a strict separation of only commands handling state changes and queries returning data. The core principle is to recognize that commands (actions that change the system's state) and queries (actions that retrieve data without altering the state) have different requirements and should be treated differently. In the context of CQRS: Commands typically represent operations that modify the system's state, such as creating, updating, or deleting records. These operations may or may not return an ID or other information depending on the specific use case or system design. It's perfectly acceptable to return data if it's necessary for the application's requirements, and CQRS doesn't forbid this. Queries, on the other hand, focus on retrieving data from the system without altering it. They are responsible for providing information to the client. In summary, CQRS encourages separating the handling of commands and queries because they have different purposes and requirements, but it doesn't strictly enforce a specific way of returning data or IDs. The exact design and implementation can vary depending on the application's needs and architecture.
@MilanJovanovicTech
10 ай бұрын
Nice summary!
@lucasfelixcarvalho2057
Жыл бұрын
Awesome! .. we as (new) developers sometimes forget that libraries and packages just put something fancy and complicate things around some concept that was written on books many years ago
@MilanJovanovicTech
Жыл бұрын
I still think MediatR is great!
@gianlucalocri
Жыл бұрын
You know what Milan? Today I took the step. You are officially my first ever patreon creator I'm subscribed to. Your videos are very useful to me so I decided to support your work!
@MilanJovanovicTech
Жыл бұрын
Thank you so much, Gianluca! I'll make sure to keep the video quality & code to a high standard. 🚀
@MizenDaCat
Жыл бұрын
Thank you! This is exactly what I've been thinkning while researching the subject for a new project. Every article on Vertical Slice Architecture or CQRS always starts out with Mediatr. But I don't need all of that extra depedency or complexity in this particular project.
@MilanJovanovicTech
Жыл бұрын
I hope this'll help people seeking salvation from MediatR 😁
@justtomi-qp8qj
Жыл бұрын
Thanks for sharing! Nice to you took a step further and implemented commands and queries in Mediatr fashion. What I am missing here, and most of the videos talking about CQRS is WHY. Why do we even have CQRS, why separation, and it's not due to single responsibility principle - that's just an outcome. Having separated Writes / Reads is also WHAT but not Why. So I would appreciate if you're willing to explain that :) Thanks again, informative!
@arunnair7584
Жыл бұрын
I use it because it results in smaller and simpler classes, and design. Additionally queries can bypass the business/domain layer. Before the advent of RESTful API (which I abhor for various reasons), for every package or DLL I used to have 2 facades - one for writing, one for reading. Separated Writes / Reads makes you use separate databases - one that is optimized for writing (SQL and NOSQL are an option) and another for querying. You querying DB design, avoids all types of joins, as it is designed for a simple select query.
@MilanJovanovicTech
Жыл бұрын
Then you should understand why separation of concerns/single responsibility is good, I'd start there
@vincentcifello4435
Жыл бұрын
Just Tomi See my attempt at clarification above.
@arunnair7584
Жыл бұрын
@@MilanJovanovicTechI have been SRP since around 1998 or so. 🙂
@PatricSjoeoe
Жыл бұрын
We are using CQRS without MediatR and works very well :)
@MilanJovanovicTech
Жыл бұрын
Are you using a similar approach to this?
@PatricSjoeoe
Жыл бұрын
@@MilanJovanovicTech Kind of. We have two interfaces for commandhandler and queryhandler that will be injected when we dispatch the query or command. :)
@PatricSjoeoe
Жыл бұрын
We going from data-logic-web design to more vertical slice and using CQRS for communicate between different modules in the service.
@akjha627
9 ай бұрын
Thank you first !!! Finally! I have been waiting to see a video where it is well explained that CQRS DOESN'T require MediatR like its shown in many YT videos. CQRS pattern version where there are separate classes for Read or Write will be most suitable for a majority of projects. IMO, CQRS where each of the commands and queries are in their own classes is just an explosion of classes. If somebody disagrees with that, there could be two reasons => 1) Either they don't have a lot of queries/commands; in that case you shouldn't even have separate classes in the first place for each query/command. 2) Or you have a lot of queries/commands, which obviously results in an explosion of classes. Even if you just have CRUD, 10 domain entities will result in 40 staggering classes. Having just 2 different classes at most for Read/Write should fulfill the architecture requirement for many projects where Read/Write happens through different DBs. Also, if the above is followed, there really is no need for a library like MediatR, unless there are other uses.
@MilanJovanovicTech
9 ай бұрын
MediatR offers more than just splitting commands/queries, that's why I like using it
@kodindoyannick5328
6 ай бұрын
Awesome content! This come clarify much things in my mind about CQRS. Thank you Milan.
@MilanJovanovicTech
6 ай бұрын
Glad it was helpful!
@microtech2448
Жыл бұрын
Thanks for the simple and to the point video.
@MilanJovanovicTech
Жыл бұрын
Glad it was helpful!
@arunnair7584
Жыл бұрын
I first started using a CQRS like approach around 2007. Never ever felt the need for MediatR.
@MilanJovanovicTech
Жыл бұрын
I like using MediatR for the other features it has
@arunnair7584
Жыл бұрын
@@MilanJovanovicTech I get why people use it. But most of our CQRS code is generated at compile time and the generated Command dispatcher classes is used to dispatch the commands. The mapping of command to command handlers is done in xml. Code generation saves you a lot of headaches.
@pilotboba
Жыл бұрын
@@arunnair7584 I believe there is a library that duplicates the functionality of MediatR using code generators. I don't recall the name of it.
@arunnair7584
Жыл бұрын
@@pilotboba I see. I have never come across that. Anyway our apps require sub second response times. And where ever we can find a performance boost, we move the domain logic into stored procedures. This is mainly to squeeze out every bit of performance from the system, We also have a plug and play type of architecture, where new features can be added. The architecture has served us well for more than a decade now.
@pilotboba
Жыл бұрын
@@arunnair7584 I don't see how this affects perf. Perhaps a small bit if you aren't managing your lifetimes correctly and see a lot of l2 and l3 garbage collection. But, more, smaller classes isn't going to cause any noticeable perf issues. I think Nick even covered this in one of his videos.
@nikogj9495
Жыл бұрын
The litterature about CQRS motivates the separation of queries and commands because you would eventually need separated *models* from reading and updating the information. Yet, I have not found different *models* in your video, you only broke the repository's implementation. Still, there is still only one Book entity that is used in both query and command scenarios. I would have liked seeing different models (because for me, that's the most important part) of that Book concept, one model that is used for reading Books, and some other model for updating Books. Once you do that, I don't even think it's necessary to apply CQS at the repository level anymore.
@MilanJovanovicTech
Жыл бұрын
What does a different model mean for you?
@nikogj9495
Жыл бұрын
@@MilanJovanovicTech The way I understood it, is mainly the entities. For example, for querying scenarios, having a BookDisplay, BookSummary, etc.., and for commands, Book.
@jamesroot9777
Жыл бұрын
@@nikogj9495 I think what you're referring to is the response and request models for reading, creating and updating the Book entity.
@MrPayTune
Жыл бұрын
I enjoy watching your videos are night before going to bed. Thanks for sharing. I have one question, How would you handle a dbcontext that is static?
@MilanJovanovicTech
Жыл бұрын
When would you have a static DbContext? I think that's a bad idea since it will get bloated over time (the ChangeTracker)
@MrPayTune
Жыл бұрын
@@MilanJovanovicTech sorry i forgot the "not" somehow. so not static. Im not crazy enough yet to use a static db :)
@abdulnaserramadan37
Жыл бұрын
Clearly and simple, Thank you.
@MilanJovanovicTech
Жыл бұрын
Glad you liked it! :)
@noble_mickmick8889
6 ай бұрын
Thank you it's very clear now :)
@MilanJovanovicTech
6 ай бұрын
You're welcome!
@saulolima6874
Жыл бұрын
Thank you! Clearly and precise.
@MilanJovanovicTech
Жыл бұрын
Glad you liked it!
@dannevesdantas
5 ай бұрын
Exceptional explanation!
@MilanJovanovicTech
5 ай бұрын
Glad it helped!
@R3troseer
3 ай бұрын
🎯 Key Takeaways for quick navigation: 00:00 *📚 CQRS is not about mediator, separate databases, or event sourcing; it's about command query separation (CQS).* 02:17 *🔄 Command Query Separation (CQS) emphasizes separating methods for reading (queries) and updating (commands) data in your code.* 04:06 *🧱 CQRS builds upon CQS by segregating commands and queries into separate classes or objects, enhancing clarity and focus in your codebase.* 06:51 *🛠️ Separating commands and queries enhances code clarity, enforces the single responsibility principle, and doesn't necessitate separate databases or event sourcing.* 08:09 *🔧 Extending CQRS involves creating separate objects for each command, further emphasizing logical separation and maintainability.* 12:44 *📝 CQRS boils down to logically separating objects responsible for writing data from those responsible for reading it, promoting code clarity and maintainability.* Made with HARPA AI
@MilanJovanovicTech
3 ай бұрын
Cool
@misaghn8027
10 ай бұрын
You are the best. thank you for this beautiful video.
@MilanJovanovicTech
10 ай бұрын
Thank you too!
@majormartintibor
Жыл бұрын
Very nice and clear video. Well done.
@MilanJovanovicTech
Жыл бұрын
Thanks a lot! :)
@RoyZASTEROiD
22 күн бұрын
Did u maked any video about using 'iendpointroutebuilder' extension, place of classic controllers?
@MilanJovanovicTech
22 күн бұрын
Try this one: kzitem.info/news/bejne/pKF9rIprm5eclY4
@RoyZASTEROiD
22 күн бұрын
@@MilanJovanovicTech thank you very much.
@Blisstim
10 ай бұрын
Let's say I want the command methods to be separatly scalable from the query commands. In that case I would have to create 2 different microservices right?
@MilanJovanovicTech
10 ай бұрын
Yup, you'd need to split them into separate services. Most of the time, you probably won't need that.
@ronyrodriguez4472
2 ай бұрын
I implemented CQRS with mediatR and it was an arduous path, it was not agile.
@MilanJovanovicTech
2 ай бұрын
Interesting, I find it quite awesome 😅 Does take some getting used to, but it's really a request message and a handler. MediatR takes care of the rest.
@faisal3374
Жыл бұрын
by creating that much objects (Command) doesn't it effect the performance ?
@MilanJovanovicTech
Жыл бұрын
Not nearly as much as one round trip to the database will
@Tamer_Ali
4 ай бұрын
Should I use Filter instead of PipelineBehavior in this situation?
@MilanJovanovicTech
4 ай бұрын
Or regular middleware?
@Tamer_Ali
4 ай бұрын
@@MilanJovanovicTech what if we want to get the result of the request to do caching for example?
@user-rm4qp3ub1e
8 ай бұрын
Hey, nice video! Just a doubt, is instantiate a "command" class good in these scenarios ? I mean the garbage collector will make his job when the request ended no ? because for me even looks clearer than the mediaTr approach that uses reflexion so you can't go to de command directly from the call
@MilanJovanovicTech
8 ай бұрын
No indirection is a benefit
@user-rm4qp3ub1e
8 ай бұрын
@MilanJovanovicTech Yep, thats what I wanted to say, I prefer instantiate the class reather than use MeditR, sorry my english is terrible hahaha! keep going with your tutorials!
@nove1398
Жыл бұрын
Very clear explanation at all levels of the CQRS co fusion. Nicely done
@MilanJovanovicTech
Жыл бұрын
Thanks buddy!
@ala24531
Жыл бұрын
What other benefits does CQRS add other than separating the code into logical chunks?
@iamjashin
Жыл бұрын
There are two main ones: First it enables you to use different database as a source of data for queries. (although one may argue that you can accomplish the same in service). The second (More important one) is that instead of having nasty services with thousands lines of code and dependency injection nightmare we end up with clean classes which obey single responsibility principle
@EekChocolate
Жыл бұрын
That IS the benefit. When you have a bunch of complex business logic that needs be performed during the handling of one request, you may want to separate it into its own class to make your source code less of a cluttered mess. Let's use books as an example like Milan did in this video. Say you're running a web app for a large bookstore. When that bookstore has a new book added to its inventory, the staff don't just record it in the database and forget about it. There are a number of other things that can happen when a book is added: * the book is added to the "New Books" section of the bookstore's website's front page * the book is added to a weekly newsletter publication * the book is added to a search engine and recommendations algorithm * the book is removed from a list of expected arrivals from an integrated inventory management system Et cetera. Et cetera. Like others have said, the CQRS pattern is meant for large, enterprise-scale applications where seemingly simple events can have a ripple effect across the entire application. In those cases, you want to compartmentalize those events and have classes that handle them individually so that you can test them more easily.
@MilanJovanovicTech
Жыл бұрын
That is the benefit, you just have to wrap your head around it
@IAmFeO2x
Жыл бұрын
I‘m sorry to say this, but this video totally misses the point. CQRS is about having different models for querying and manipulating data, and not splitting up data access methods into different Command and Query classes. Consider a scenario where a company develops a new product and several departments need to work together in a process which might look like this: marketing identifies that a new product might be a good fit for the market, so they create it. The technical planning team then adds plans on how to build the new thing, production then adds infos about the steps needed and machines to use and how fast it can be produced, the safety department adds infos about regulation in different countries, and management finally reviews and gives green light. This complicated process involves several tables in a relational database, and in the different steps of the process, you would have seperate models for accessing these tables for the different domains. You would have several entities accessing the same tables/views. For example, the safety department shouldn't be able to manipulate data for the technical planning team, but it can view the data to be able to do all things concerning regulation. This is explicitly expressed in the data access model: if you are using EF Core, you would have dedicated entity classes which only encompass the columns the safety department can actually change, and dedicated read entities containing the columns that the safety department are able to see. That's what CQRS is about.
@MilanJovanovicTech
Жыл бұрын
That's a nice explanation, Kenny!
@yonatandaniyel5640
Ай бұрын
MediatR can become such a mess but also cam be useful if a single command needs to be processed in multiple flows, such as db write and raising events. Still I find it is overused and overly complicates your codebase.
@MilanJovanovicTech
Ай бұрын
I love working with MediatR and never understood the hate 😅
@TrockeyTrockey
2 ай бұрын
One note: for CQS, you usually could have different model for Reading and Writing. In your sample, the model was the same: Book. In real life, you usually need to have different model, like for read cold be BookWithDetails (example to carry, number of books available at store)
@MilanJovanovicTech
2 ай бұрын
CQS or CQRS?
@CesarDemi81
Жыл бұрын
The problem with the sample you created there is that it is extremely simplistic and unrealistic. Any real world app will have some dependencies, like DbContext if using EF Core or a DbConnection for Dapper or any other kind of service the app depends on, so now you will have to inject all of that in the command, which is expected to only hold the data it will provide later to the handler, but also with dependencies that will need to be provided in each of the endpoints. For this you will then create some generic stuff to reuse everywhere so you don't repeat yourself so much, and what you end up with? With another home-made version of MediatR 🙃 In the end, you can do CQS/CQRS without MediatR, that's correct, but you end up either making your code more cumbersome or you end up reinventing the wheel to make your own (dumbed-down?) version of MediatR... So implementing MediatR is more a convenience/advantage than a requirement.
@thatojadezweni
Жыл бұрын
not necessarily. a route that one can take it to treat the various commands/queries as standalone services in a sense and inject the command/query in each endpoint then simply inherit from some “IUseCase”-like interface and just register each “service” that implements it via DI with a bit of reflection.
@CesarDemi81
Жыл бұрын
@@thatojadezweni like I said: reinventing the wheel all over again with your own home-made version...
@MilanJovanovicTech
Жыл бұрын
You have to use simple examples when explaining concepts, otherwise from my experience, people will completely miss the point.
@CesarDemi81
Жыл бұрын
@@MilanJovanovicTech I do get that and for the most things that's all right, is just that people later tend to take the simplest samples to the letter and I was just pointing out why in the majority of the real scenarios MediatR is chosen for implementing CQS/CQRS... It was not precisely a critic to your video (which was very nice, btw), but an observation comparing to real life implementations, mainly due to many of the comments oversimplifying this. Cheers!
@vincentcifello4435
Жыл бұрын
“What is the first thing that comes to mind when you hear CQRS?” Is this a collaborative domain?
@MilanJovanovicTech
Жыл бұрын
What would an example of that be?
@kinax2
11 ай бұрын
why are you using Guid, isn't long is better?
@MilanJovanovicTech
11 ай бұрын
Better is debatable
@vivekkaushik9508
Жыл бұрын
Clearly CQRS is not meant for 70-80% projects out there which are medium to small scale projects. It only adds complexity without much benefits.
@booby163
Жыл бұрын
Do you think if it is a simple to medium project we should implement business logic directly in the controllers/endpoints or injecting a service with CQS approach instead?
@Andy01010
Жыл бұрын
I’d say it’s the other way around. Most apis would benefit from it - separating concerns is always a better default than not. You can knock up a command/query handling via DI very easily, nothing fancy but it will work very very well, no need for a fully featured Mediatr.
@nunodecarvalho8658
Жыл бұрын
CQS and CQRS are good for every project, it’s a choice it’s not a rule or salvation. If you do it just don’t use the wrong tools to make it hard.
@MilanJovanovicTech
Жыл бұрын
The benefits are conceptual, and to me they are worth it
@vivekkaushik9508
Жыл бұрын
@@booby163 It depends. If there is scope of improvement or further development then YES we should be separating concerns however we must not complicate our project from the very beginning with all this DDD, TDD, BDD, CQRS, MediatR etc stuff.
@leftjabrighthook
5 ай бұрын
Sure simple if you use a static database like you did. That is not REAL life though. No one does that. Lets see how simple this video is if you need to inject services into your handle method. I'm no fan of Mediatr but come on, Mediatr is a lot more simple then the method shown here. Hell, you should have made it more simple and cleaner by making your Handle methods static!
@MilanJovanovicTech
5 ай бұрын
Let's do a Part 2 then!
@margosdesarian
7 ай бұрын
What a load of old ballcocks - in every system i have built a delete action returns a class that lets the caller know whether it succeeded or failed, and if it failed what the reason was. Because in anything more complicated than a todoitem application there might be many reasons why a delete should be rejected - the idea of returning a void in this case is just dumbing down.
@MilanJovanovicTech
7 ай бұрын
There's a difference between "theory" and what actually makes sense in practice
@margosdesarian
7 ай бұрын
@@MilanJovanovicTech Yeah - sorry for the flame
@FcoMp
2 ай бұрын
you made this seems so unnecessary
@MilanJovanovicTech
2 ай бұрын
it was very necessary
@andreisv
Жыл бұрын
Where the create book record stands? It should return the newly created guid at least 🤔
@MilanJovanovicTech
Жыл бұрын
That's okay
@andreisv
Жыл бұрын
@@MilanJovanovicTech could it then return the newly created entity then? We had a debate with one of my coworker on this, I stood for just the guid so the next call would retrieve the full record while he said it is a redundant call
@AnythingGodamnit
4 ай бұрын
No one seems to explain *why* commands can’t return data, nor address the elephant in the room: if they can’t return data, how would your example look if books had autogenerated IDs? If clients send an update command, why should they then need to query to see the results? If the command is long running, how the hell can the client even be informed about progress if it has no handle for the execution? I know you said be pragmatic but that just makes the entire premise of commands never returning data completely bogus. Sorry, a bit frustrated after spending over an hour watching CQRS videos and everyone is just talking about the obvious and showing crazy levels of abstraction to support the pattern but never actually talking about the more interesting questions that arise when applying this principal in the real world.
@MilanJovanovicTech
4 ай бұрын
Check the first two sections here: www.milanjovanovic.tech/blog/cqrs-pattern-with-mediatr
@MilanJovanovicTech
4 ай бұрын
"This doesn't mean a command can never return a value. A typical example is popping a value from a stack. It returns a value and changes the state of the system. But the intent is what matters here. CQS is a principle. You can follow this principle if it makes sense, but be pragmatic."
Пікірлер: 112