Thank you Ami, i watch all videos in playlist "REST API following CLEAN ARCHITECTURE & DDD Tutorial" and help me understanding the Clean Architecture.I really liked your teaching, and like you use the most relevant and newest package in this lessons, such as Mapsters, MediatR, FluenValidations, EntityFramework. I will use this learnings to develpoment my capstone project.
@indeem1507 Жыл бұрын
I really liked how you explained and showed how to implement domain events. Whats kind of missing for me is, why? Because you did not implement the notification Handler i could not really see how domain events are useful.
@irfanshaik13025 ай бұрын
From what I understood, the handler will contain the logic of adding the menu id to particular dinner(using dbcontext) as mentioned in the beginning of the video. So simply put, handler also contains db operations, which are outside the scope of the aggregate, but these all operations will run at once because we are calling these handlers before save changes, and they should run at once because they are related operations.
@vincentcifello4435 Жыл бұрын
1)"Aggregates are transactional boundaries" Menu and Dinner are separate aggregates. Therefore, they are separate transactional boundaries, by definition. Yet, they are being saved within one database transaction. This is self-contradictory. It is also a seed of destruction.. 2)"Other solutions require a lot of ceremony" This entire video substitutes an elaborate, in process, technical solution, ultimately described as "a lot of boilerplate code", in order to avoid a minimal transaction script that is exactly the same, except that it is explicit. Dinner.Add(myMenu) Menu.Dinners.Add(myDinnerId) ----this one line is the reason for this video dbContext.SaveChanges() 3)Dinner aggregate holds a MenuId That is all that is needed for the relationship between Dinner and Menu. Having a Menu aggregate holding a list of DinnerIds duplicates data. This appears to be the reason that both of these aggregates are being saved in one transaction. Seed.Of.Destruction. I am criticizing the way DDD gets implemented, not Amichai. It is always a convoluted, self-contradictory mess.
@salarrabbal40597 ай бұрын
Thank you for providing such a comprehensive explanation. Over the years, I've encountered various implementations of this concept, yet many seem detached from practical application in the real world. For instance, in your approach, what would happen if domain events were cascaded, or situations arose where the use of IDbContextFactory to handle aggregates in batches precluded injecting the current instance of your Repository in event handlers? In my experience, addressing these challenges often leads to encountering significant accidental complexities, which may prompt a shift towards embracing eventual consistency over immediate event publication prior to saving changes. Once more, I value the insights shared in your informative videos.
@LoZioIAR Жыл бұрын
Thank you as usual!! Should be very good if you'll add a windows that show what key are you writing!
@mohamedal-qadeery6530 Жыл бұрын
Hello i want to start this playlist how many videos are remaing for this to finish ? this the best content on youtube !
@alan- Жыл бұрын
I really do appreciate the content, but following along with this is made unnecessarily difficult by there being many hidden changes in the underlying code from episode to episode, meaning that it is impossible to follow without being a member on patreon and even with that, it is very awkward and off-putting. It would really help if you could put an on-screen summary sheet of what or where the changes are, so we don't bump into them and then have to piece together what the differences are from the patreon source code in order for the code to run. I am very grateful for the content, it is great to have such in depth detail on a complex topic, but it would be easier to follow along if there was a brief summary sheet at least outlining where the additional changes are. The most significant changes were when many of the IDs changed from guids to strings between one set of episodes, then in a later episode, they had changed back to guids again.
@zero8_84 ай бұрын
Good afternoon! I really liked the course! Is it possible to find out if there is a sequel? I would like to go through the following stages, where all the functionality of the application will be analyzed in detail and the final architecture will be shown. I am especially interested in whether not only authorization and authentication will be covered, but also other important functions.
@avi727810 ай бұрын
what is the app that you're using for presentation in your video?
@DrHeinzDoofenshmirtz Жыл бұрын
Great! I would really have liked to hear you talk about (maybe with an example) how other entities would react to the domain event. For example, as you are talking about the two-way reference issue. Would the Menu be created and store a reference to the DinnerId, and when the event is triggered, a specific event handler would take the dinner id, fetch the dinner from the database, and then update its reference to the Menu? Or I guess it is the other way around: When the Dinner is created and a DinnerCreated event is fired, the Menu would add it to its inner list of dinners?
@amantinband Жыл бұрын
Thanks! Yup the second one. The event handler would sit under the Menus folder in the application layer (FYI for Patrons: the Patreon source code includes this exact example)
@DrHeinzDoofenshmirtz Жыл бұрын
@@amantinband That is a very good reason to become a Patreon 😊
@z_prospective160 Жыл бұрын
Very cool! I like it! The overhead of the structure is worth it.. and hopefully you are able to put this boilerplate in a common library you can reference from a nuget feed. I never thought to publish the domain events from persistence layer as a part of save changes. I have done things like modify the entity's audit fields in the save changes method before. This is very cool and I'll be using this for sure. thank you!
@novelhawk Жыл бұрын
Way cleaner approch on the Publish logic in my opinion is the following: - Remove Clean method and instead create a Drain method that cleans and returns what it has cleaned - Replace linq with var events = dbContext.{...} .SelectMany(entry => entry.Entity.DrainDomainEvents()) .ToArray(); // publish events
@amantinband Жыл бұрын
I've taken a similar approach in some projects. If you don't need to read the events (without "popping" them), what you suggested is a safer approach, IMO.
@pilotboba Жыл бұрын
@@amantinband So the domain events could be a stack instead of a list?
@ferventurart Жыл бұрын
Great work Amichai!! But whats happen if you have identity Id. For example, if we follow this tutorial we always created at entity with Id 0, and if on our domain event want insert on another table it throws error.
@reshiefaisal1477 Жыл бұрын
Hey man it's a great help that you're making these videos. These videos have helped. I kindly request to make a video on Test Integrations as well. That will be very kind full of yours.
@amantinband Жыл бұрын
I have a whole sub series planned on testing. This will include integration tests as well
@reshiefaisal1477 Жыл бұрын
Thank you. That will appreciated.
@patrykk.4630 Жыл бұрын
Hi, I am back after a long pause. Yesterday I made changes to my aggregate roots (identity paradox) and my mapper stopped working for AuthenticationResult -> AuthenticationResponse. It says 'Cannot convert immutable types, please consider using MapWith'.
@TheOneAnOnlyGuy Жыл бұрын
How do you justify adding MediatR to the domain? That is a dependency that does not belong in the domain, imo.
@Marfig11 ай бұрын
There is nothing wrong about adding external library dependencies to the domain layer. Even more so if they are utilitarian libraries like MediatR. One common misconception is reading too literally the ol' adage "the domain layer shouldn't depend on anything". What that should read is, the domain layer shouldn't depend on any other structural layer of your project. It's well within DDD best practices to support your domain layer with external libraries that don't create those dependencies, like MediatR for Domain event support. Another example are discriminated union libraries to reduce exception handling in your code.
@samehhakim4340 Жыл бұрын
👍👍👍👍👍 Thank you, your explanation is really very simple
@juliangzr4998 Жыл бұрын
Hello! thank you for your video. I have a question: How can i do to throw domain events when i delete an entity? in that case it's not possible to save the domain event inside the entity because you are deleting it. I usually delete the entity through the repository.
@CharlesSyms Жыл бұрын
Hello! I've been racking my brain with this. I have been following along all of your videos and understand the concept, but I'm hitting a roadblock when creating the migration, where it is creating a shadow property on a foreign key. This would be the equivalent in your example between dinner and reservations.
@alexlo5655 Жыл бұрын
Hey, Amichai! Great video as always!, Could you plz make the "code" screen(s) larger? I can hardly see your code.
@amantinband Жыл бұрын
Thanks! Curious if others want this as well. If yes I’ll bump the font size. thanks for the feedback, Alex 🙏🏼
@pilotboba Жыл бұрын
@@amantinband It seems fine to me, and I can zoom my screen if needed.
@alexanlp Жыл бұрын
Sorry for my question, bur which font you're using in VS Code?
@evgeniysir4220 Жыл бұрын
Great video! Thank you! Maybe not exactly on the topic of the video, but I have a problem that I don't know how to solve yet using the existing architecture. Namely: I add a function to the repository to search for an entity by identifier, I pass an identifier object to the function as a parameter (HostId hostId hostId as an example), inside the function I use FindAsync(hostId). When executed, the exception "System.ArgumentException: The key value at position 0 of the call to 'DbSet.Find' was of type 'HostId', which does not match the property type of 'AggregateRootId'" occurs. Considering that AggregateRootId is an abstract class, how to solve this problem? I would be grateful for a hint.
@kmcdo Жыл бұрын
public record TreeFell(bool madeSound) : IDomainEvent; If there's no handlers, did the event even happen? ;-)
@amantinband Жыл бұрын
HAHAHAHA Dad jokes 💪🏼
@sneigee Жыл бұрын
that awesome. thanks for this. and please try and release it early. Stay bless bro
@AlexGait Жыл бұрын
Hey, Amichai! Great video as always! Is there a reason you prefer to have Domain Events in the Entities and not the Aggregates? Will an Entity ever raise a Domain Event? Also, when do you think the testing videos will be released?
@allannielsen4752 Жыл бұрын
I too was wondering why they were not in the aggregate. The other thing I have always been told was that domain events exist inside their bounds and integration events cross bounds. It might just be semantics, but I find that coupling using this method leads to the same spaghetti this is supposed to "fix". Furthermore, I was surprised to see you adding the menu instance into the event and not just the ID, could you explain that further too please, as now you are exposing the menu domain object to outside too.
@amantinband Жыл бұрын
Thanks, Alexandros! Both approaches are very common. I've used both, and the main difference is whether the inner entities need to communicate back to the aggregate root that something happened. The main benefit of domain events in the aggregate root is a single, organized place for all events. Since we are organizing our domain layer by feature, it is clear which domain events are associated with which aggregate, which is why I prefer the Entity approach. Does that make sense?
@amantinband Жыл бұрын
@@allannielsen4752 Hey Allan. Domain Events capture an event that happened within a bounded context and are used to implement side effects on other aggregates within the same bounded context. In our application, BuberDinner *is* the bounded context and the side effects are updating zero or more aggregates within BuberDinner. Regarding event parameters - it all depends on your use case. You can pass as little or as much as you need.
@AlexGait Жыл бұрын
@@amantinband I am not sure I see the benefit, but I guess it is more of a preference. Thanks!
@pilotboba Жыл бұрын
@@AlexGait The number one benefit I see from using domain events is that it helps with single responsibility and open/closed. (probably the two most important SOLID factors). Right now, we have 1 thing that has to happen after a menu is created. If that's in the create menu handler, fine. But down the road a second thing needs to happen when a menu is created. So, now you have to edit the handler and add code to it. So, that handler has multiple reasons to change now. With domain events, you would simply add a second handler for that event. The more your code never needs to be modified to add features and just added, the better. You're less likely to break something that is already working. Anyway, this is just my opinion. Take it for what you paid for it. :)
@jamesroot9777 Жыл бұрын
Hey Amichai, absolutely love the videos. Have followed from part 1, and watched all the videos a few times already. I'm in a course right now, and we are tasked with wiriting a simple Forum RESTful API, but I got invested into what you are doing and wanted to adapt it. I've since hit a roadblock. Could you give me some advice on how I can scale down the project so it makes sense for someone whose closer to a beginner like myself? Would the User, Post and Comment aggregates need to follow what you've done so far, including the AggregateRoot, Entity and Value Object models? How do I handle roles, as in "Admin" and "Basic User"? What do you think I can ignore from your DDD, keeping in mind my project is extremely small compared to what you're doing, and we are not expected to have even half of the features and implementations you're using. (Although, I'd love to keep all of 'em, favourite is ErroOr). Keep the videos coming!
@mohamedal-qadeery6530 Жыл бұрын
im a beginner too but i think its going to be something similar to the guest/host aggregates where u would have value object of userId
@weilei888 Жыл бұрын
wow.great video..
@verified_tinker18186 ай бұрын
What software are you using in these videos?
@wilfriedkinda Жыл бұрын
Hi Amichai very good and informative video as always just need an open mind for me who uses mongoDb as a database how to set up an interceptor!? or what logic I can use I'm a beginner.
@TheFeljoy Жыл бұрын
An interceptor is just a nice way of adding this logic to the save method of entity framework. The simplest way would be to create a new method that calls whatever save method you use for mongodb inside it and calls publish domain events just before that. Then you always use your custom save method instead of the default one. For bigger projects with many contributors it’s important to build things in a way where you couldn’t do things the wrong way anymore (because it’s not possible) but for your own project this is much less important.
@Steven-hq6df5 ай бұрын
I'd be interested in an implementation without depending on ef core
@mikefellowes891010 ай бұрын
What is your opinion on request handlers orchestrating changes to multiple aggregates directly, rather than using domain events to orchestrate that logic? Using domain events exclusively to communicate between aggregates could make understanding the flow of a particular use case challenging, couldn't it? If the use case logic is clear then it seems to me that using one handler would be the best approach. I can see that using domain events is flexibile, along with the advantages of the pub-sub nature of INotification, but do you think there is a place for both approaches?
@amantinband10 ай бұрын
Completely agree. That's why I have the following section in Clean Architecture template on GitHub: "Note: Eventual consistency and the domain events pattern add a layer of complexity. If you don't need it, don't use it. If you need it, make sure your system is designed properly and that you have the right tools to manage failures."
@mikefellowes89109 ай бұрын
Thanks for the reply @@amantinband - fantastic videos btw, you have a new subscriber! For anyone interested, I came across this Microsoft article making the same argument for domain events. Since I cant paste the link here, do a web search for the section in the article titled: "Domain events as a preferred way to trigger side effects across multiple aggregates within the same domain".
@batiku1 Жыл бұрын
Why can't we pubish the domain event(s) right from the domain layer?
@TuanNguyen-ed9rb3 ай бұрын
because your domain isn't persisted to the database yet. You don't want to send an email to customer before their order is successfully saved
@parthadutta11688 ай бұрын
How to implement domain events when domain entities and persistence entities are different, i.e. domain entities are persistence ignorant?
@issacproton788511 ай бұрын
very insightful!
@SureshKumar-rz7dn Жыл бұрын
Great Video as always :-) Can we use this pattern for sending events(integration event) externally to a service bus queue?
@ZeBobo5 Жыл бұрын
You can add bus publishing in a domain event handler. And why not inside another assembly
@issacproton788511 ай бұрын
would you like to share how do you use Tools like a pro, it feels like Vim on VS Code as well as Visual Studio when you use it.
@issacproton788511 ай бұрын
I loved it!
@PelFox Жыл бұрын
There's still a problem with consistency. Events could be published and then SaveChanges fails or the SaveChanges fails and some process within an event handler fails. Everything also runs in process, so need to keep that in mind if you have users waiting for a call.
@amantinband Жыл бұрын
Note that all handlers and inner “save changes” are part of the original transaction. If any fail, all changes are rolled back. As long as all side effects are on aggregates within the system, this solution resilient to failures
@PelFox Жыл бұрын
@@amantinband Yes, if they all act within the same transaction and database. What I often see is domain eventhandlers publishing integration events, those could fail and that would result in state changes without messages being published.
@amantinband Жыл бұрын
Exactly. I talk about this somewhere in the video
@modgenesis3868 Жыл бұрын
why would you have domain events in the domain objects, the logic could also be handled in the command handlers right? The thing about this approach is that code gets executed at place A but then somewhere in the app it gets fired in another part, this will be hard to debug in the future. But Thanks for this video man!
@stunna4498 Жыл бұрын
your domain events will be called in the domain objects itself. but the code that handles that event will be in the application layer so it won't be hard to debug since you will allways know where that event is handled
@amantinband Жыл бұрын
Yes. The 2 main approaches are orchestrating all the changes from the handler and the domain events pattern I demonstrated on this video. Which is better? That depends on your preference, app, and goals.
@pilotboba Жыл бұрын
See my reply above. The reasons are to keep your code more solid by following the single responsibility property and the open/closed principle.
@zakustolondoo8 ай бұрын
Hi Amichai, How can I get the source code as a member?
@amantinband8 ай бұрын
Hey man! It’s a perk for patrons. Being a member gives you only early access to videos as I upload them
@zakustolondoo8 ай бұрын
@amantinband Apologies if I joined the wrong group. I joined because I need access to the source code. How can I transfer my subscription to patron without having to pay again?
@amantinband8 ай бұрын
Moving the subscription isn’t possible. I think you can cancel the membership and you won’t be charged (or maybe you’ll be charged only for the day you were a member)
@marcinz9379 Жыл бұрын
Hey, I have question about DDD. For example we have aggregate Blog, and this Blog has many Posts, and any Posts has many Comments. How to add new Comment to Post? Blog is my AggregateRoot. And now i have problem. I don't want to get from db my whole Blog with all Posts and nested Comments. It's not efficient and also I don't have any aggregate rules for Comments. For example we have: AddCommentCommand(PostId PostId). Can I simply get this Post from db, create new Comment object and save this to db? Or it all should be under our Blog aggregate?
@stunna4498 Жыл бұрын
in this case comment should be an aggrregate itself and you would have a reference to the Post by using the PostId. Then when you query the post you would go to the comment repository and get comments by id or whatever.
@amantinband Жыл бұрын
Check out my videos on domain modeling. As Joel suggested, You would probably want the Post and/or the Comment to be an aggregate root as well (one of the reasons we prefer more aggregates is not having to read big aggregates when we need to make an update to a nested entity)
@marcinz9379 Жыл бұрын
Thank you guys
@nicolasundiano8406 Жыл бұрын
@@amantinband but what happens if we want to query related data of the Post Aggregate, for example the list of Comments Aggregate included. Do we have to do multiples queries to the db and put them in a PostWithCommentsResponse?
@pilotboba Жыл бұрын
@@nicolasundiano8406 Why are you querying it? For your query side or for your command side? If for the query side, you can create a read model that just does a simple query on the db and doesn't use the aggregates at all.
@timur28877 ай бұрын
Don't materialize enumerable twice or more in one function
@ANTONZUBAREV10 ай бұрын
Отлично! Но слишком сложно/ Great! But it is a too diffcult