Using Domain Events To Build A Decoupled System The Scales

  Рет қаралды 23,565

Milan Jovanović

Milan Jovanović

Күн бұрын

☄️ Master the Modular Monolith Architecture: bit.ly/3SXlzSt
📌 Accelerate your Clean Architecture skills: bit.ly/3PupkOJ
🚀 Support me on Patreon to access the source code: / milanjovanovic
Scalability is important. And domain events can help you build a scalable system by allowing you to achieve a decoupled architecture. I'll show you how to use domain events and discuss the pros and cons of publishing domain events with EF Core.
Join my weekly .NET newsletter:
www.milanjovan...
Read my Blog here:
www.milanjovan...
Subscribe for more:
/ @milanjovanovictech
Chapters
0:00 The problem of coupling
0:43 Creating a DomainEvent base class
1:44 Adding the OrderCreatedDomainEvent
3:01 Adding the LineItemRemovedDomainEvent
3:50 Domain events naming convention
4:13 Entity class for raising domain events
5:14 Raising domain events in Order entity
6:27 Handling domain events with MediatR
9:11 How are we going to publish domain events?
11:09 Decision: Publishing BEFORE or AFTER persisting changes?
12:22 Publishing domain events with IPublisher

Пікірлер: 91
@MilanJovanovicTech
@MilanJovanovicTech Жыл бұрын
Want to master Clean Architecture? Go here: bit.ly/3PupkOJ Want to unlock Modular Monoliths? Go here: bit.ly/3SXlzSt
@majormartintibor
@majormartintibor Жыл бұрын
Milan I am really looking forward to a full course from you, building an entire application with DDD, Rebus, RabbitMQ etc etc. I hope you will make one! Great video btw!
@MilanJovanovicTech
@MilanJovanovicTech Жыл бұрын
It's coming in a few months! :) Starting recording May/June
@rohit704
@rohit704 Жыл бұрын
Thanks for asking , I was looking the same :)
@MilanJovanovicTech
@MilanJovanovicTech Жыл бұрын
@majormartintibor Course is nearly ready, coming out in a few weeks. I'm calling it "Pragmatic Clean Architecture"
@MilanJovanovicTech
@MilanJovanovicTech Жыл бұрын
@@rohit704 Coming out soon, pay attention to my newsletter for the launch
@rustamhajiyev
@rustamhajiyev Жыл бұрын
Speaking about trying to saving entity and domain events together, that is why I prefer using event sourcing :) you deal only with domain events and rebuild entities based on them.
@MilanJovanovicTech
@MilanJovanovicTech Жыл бұрын
If only it were as beautiful as it sounds 😅 There are many nuances with event sourcing that can be easily overlooked.
@rustamhajiyev
@rustamhajiyev Жыл бұрын
@@MilanJovanovicTech of course, it's not a silver bullet :)
@alexisnarvaez
@alexisnarvaez 2 ай бұрын
@@MilanJovanovicTech But man, please, beare with me. You are telling your audience to store events with EF Core and then develop a full backround service that polls for events tand tries to publish somewhere else... how is that easier than simple go event sourced and use something like EventStoreDB to handle persistence, and subscription of events?
@eser-sahin
@eser-sahin Жыл бұрын
Clean and simple implementation, thanks for sharing with us.
@MilanJovanovicTech
@MilanJovanovicTech Жыл бұрын
You're most welcome
@alan-
@alan- Жыл бұрын
I'm really liking your videos. Always clear and concise.
@MilanJovanovicTech
@MilanJovanovicTech Жыл бұрын
Thanks a lot, Alan :)
@user-zm2dh8uz6p
@user-zm2dh8uz6p Жыл бұрын
Hey Milan, really nice video. I'm looking forward for this new robust impl of the outbox pattern. Thanks for making such an awesome content, free.
@MilanJovanovicTech
@MilanJovanovicTech Жыл бұрын
Thanks, Wil :) I'll try to make it good 😁
@juancamiloromerosarmiento2711
@juancamiloromerosarmiento2711 9 ай бұрын
You are the best man ... !! learning a lot from this collection of videos !! I feel my self like an expert in DDD ... hahaha
@MilanJovanovicTech
@MilanJovanovicTech 9 ай бұрын
You rock!
@robertmrobo8954
@robertmrobo8954 Жыл бұрын
Looking forward to an indepth Outbox Pattern video. ❤
@MilanJovanovicTech
@MilanJovanovicTech Жыл бұрын
Recording it soon 😁
@MJ-yx4ut
@MJ-yx4ut Жыл бұрын
@@MilanJovanovicTech What will the difference be against your previous video about Outbox Pattern?
@adriano.digiere
@adriano.digiere Жыл бұрын
Hi Milan! Great video. Is there any video in which you talk about integration events? Thanks for the content.
@MilanJovanovicTech
@MilanJovanovicTech Жыл бұрын
Hmm, I don't think there is such a video (yet)
@adriano.digiere
@adriano.digiere Жыл бұрын
@@MilanJovanovicTech Looking forward for it 😀
@alexmadnix
@alexmadnix Жыл бұрын
TQ Milan^^ 14:01
@MilanJovanovicTech
@MilanJovanovicTech Жыл бұрын
Thanks 😁
@empireofhearts
@empireofhearts Жыл бұрын
After watching couple times, im still left with impression that nothing changed from start to end, we are still raising event after we saved changes to the DB except at start, specific event was raised in domain layer probably scattered and at end all events are raised by iterating events in the persistence/infrastructure layer. at both times we would throw any exception in the events back to the UI/calling layer. Am i missing something? Effectively the title of the video is achieved in a way but the drawback still exist. i think the drawback is true for any in memory event bus.
@MilanJovanovicTech
@MilanJovanovicTech Жыл бұрын
Yes, there's that drawback you noticed with this implementation. The Outbox pattern solves that issue
@empireofhearts
@empireofhearts Жыл бұрын
@@MilanJovanovicTech thank you for the information. so you planning to show that in coming in upcoming video?
@MilanJovanovicTech
@MilanJovanovicTech Жыл бұрын
@@empireofhearts Yes 😁
@nove1398
@nove1398 Жыл бұрын
Lesser of two evils Indeed, i prefer the approach that is after and as some clean up
@MilanJovanovicTech
@MilanJovanovicTech Жыл бұрын
There's a way to fix though
@nove1398
@nove1398 Жыл бұрын
@@MilanJovanovicTech will there be a video on that? Or did you already have the video posted?
@LucasHenriquedeBrito
@LucasHenriquedeBrito 10 ай бұрын
Question. I have a CreateSomethingAHandler and during this handler, my domain has raised an event. So I will have AEventHandler. During AEventHandler, can this AEvent raise another Event? like a chair event? Does it sound like bad practice? CreateHandler -> Domain raise an event-> EventHandler-> Domain can Raise another EventHandler?
@MilanJovanovicTech
@MilanJovanovicTech 10 ай бұрын
In general - it's not a bad practice. But I would definitely consider using an Outbox. Chaining so many domain events can lead to a pretty large transaction.
@pabloferrando6471
@pabloferrando6471 Жыл бұрын
Hi, Milan! This is clear for use cases where you invoke methods on the aggregate root, such as create() or addItem(), where you can publish the corresponding event inside the entity producing it, but how would you approach an OrderDeletedEvent? Would you need to pass through a delete() method or something alike?
@MilanJovanovicTech
@MilanJovanovicTech Жыл бұрын
Yeah, that would get the job done. Just expose a method that raises an event inside.
@remcobrosky1018
@remcobrosky1018 Жыл бұрын
Really like your content and views on real world architectural challenges. Isn”t this specific approach creating a dependency on MediatR in your domain model? I consider this a framework dependency that I would avoid.
@MilanJovanovicTech
@MilanJovanovicTech Жыл бұрын
Yes, but it's a tradeoff I'm willing to make for the benefit of simplicity
@andersjuul8310
@andersjuul8310 Жыл бұрын
Hi Milan, perfect timing; I was just introducing DomainEvents to an otherwise Clean Architecture yesterday. Pretty much as you present it. However, a consideration: One of my events is change of State and I was debating with myself whether I should have a StateChangedDomainEvent or multiple like StateChangedToAuthorized, StateChangedToTerminated etc. I guess "it depends", but do you have any thoughts you'd like to share?
@MilanJovanovicTech
@MilanJovanovicTech Жыл бұрын
I'd say it depends on how you handle it? Also, the State is obviously a part of a larger object/entity/aggregate. Maybe OrderState? So it should be OrderAuthorized/OrderTerminated more so than StateChanged
@josecarlosmacoratti
@josecarlosmacoratti 5 ай бұрын
Create your DomainEvent implementing INotification makes the Domain tightly coupled to MediatR and any changes to MediatR affect your domain and I think it is not a good practice but I could be wrong
@MilanJovanovicTech
@MilanJovanovicTech 5 ай бұрын
I prefer being practical rather than dogmatic. What could possibly change with MediatR? Will pub-sub become unpub-unsub? (sorry for being ironic, but 😅)
@chrismingay6005
@chrismingay6005 Жыл бұрын
Very clear video as always, thank you! Generally speaking would it be better to not pass the cancellation token to _publisher.Publish ? By that I mean if the system has got as far as saving the changes to the database we do not want to allow it to back out of publishing the domain events.
@MilanJovanovicTech
@MilanJovanovicTech Жыл бұрын
That's a very valid concern
@Sara-po1jd
@Sara-po1jd 7 ай бұрын
thank you for a nice video, I have a question regarding using the MediatR in the domain layer. i kknow that that domain layer should not have any integration with other libraries, can you please explain why in your case you use an external library ? I would appreciate your answer.
@MilanJovanovicTech
@MilanJovanovicTech 7 ай бұрын
It's just an interface, I can live with that
@Andy01010
@Andy01010 Жыл бұрын
Btw water to ask, do you use domain events to communicate between aggregates much?
@MilanJovanovicTech
@MilanJovanovicTech Жыл бұрын
Yes, it's very powerful for triggering side effects within a bounded context
@z0n_
@z0n_ Жыл бұрын
I am not really a fan of publishing integration-events inside domain-event handlers. I think it's better to have a clear separation between the domain- and integration-events. Domain-events are handled as a part of the transactions and integration-events are published after the transaction has completed. It still does not fix the problem where publishing the integration-events fails but you could always switch to using outbox pattern. How about this? // Application layer class DomainEventHandler { public DomainEventHandler(DbContext dbContext) { ... } public Handle(SomeDomainEvent event) { var someEntity = this._dbContext.GetSomeEntityBy(event.Data); someEntity.Update(event.Data2); someEntity.RaiseIntegrationEvent(new SomeIntegrationEvent()); } } And inside SaveChanges() publishDomainEvents(); base.SaveChanges(); publishIntegrationEvents(); Domain-events are published inside domain layer and integration-events are published in the application layer. Domain-events handlers can be a part of the transaction and integration-events are published after the transaction has completed.
@MilanJovanovicTech
@MilanJovanovicTech Жыл бұрын
I'd rather separate integration events from the main business transaction using an Outbox, it leads to a more robust implementation
@lourenceplay9017
@lourenceplay9017 6 ай бұрын
Great video, thanks! Will there be more videos with the development of the E-shop web api? And will you add any new entities to the project? Product cart for example
@MilanJovanovicTech
@MilanJovanovicTech 6 ай бұрын
I don't think so, for the time being
@ramytawfik9168
@ramytawfik9168 Жыл бұрын
Can you please milan make a video about Threading , async and await and Parallel and multi-threading if you have time. And Thanks for all your effort
@MilanJovanovicTech
@MilanJovanovicTech Жыл бұрын
Maybe, not my forte though
@ramytawfik9168
@ramytawfik9168 Жыл бұрын
Another question please what do you mean by 'Atomic' in the latest approach, Do you mean that we will either persist the business logic and the event in the db or if there is any problem then we will rollback the business logic and also the event ?
@MilanJovanovicTech
@MilanJovanovicTech Жыл бұрын
Exactly that!
@adriano.digiere
@adriano.digiere Жыл бұрын
Hi Milan! I have one question. When we are removing a line item, this is done by a function inside the aggregate root Order. So we can call the function Raise passing the LineItemRemovedDomainEvent. How would be the approach to an aggregate root deletion (ex: Order)? We would have to expose the Raise function and call it from the handler? Thanks.
@MilanJovanovicTech
@MilanJovanovicTech Жыл бұрын
Or create a method on the Aggregate root called "Cancel"/"Remove"?
@adriano.digiere
@adriano.digiere Жыл бұрын
​@@MilanJovanovicTech This method would be responsible just for raising the event? What would prevent a programmer from deleting the aggregate root without calling this method? Thanks for the answer.
@user-cp8hr2zr5k
@user-cp8hr2zr5k 16 сағат бұрын
Hello, how can i publish domain events if i have separate domain and database models?
@MilanJovanovicTech
@MilanJovanovicTech 10 сағат бұрын
Publish when mapping from one model to the other
@BeHappyAndNice
@BeHappyAndNice Жыл бұрын
I love your channel, it is extremely useful. I have a question. How it is possible to persist an event by ef core change tracking that was raised in the rich model while the snapshot pattern is used to map the rich model to a model that is supposed to be persisted into the database?
@MilanJovanovicTech
@MilanJovanovicTech Жыл бұрын
EF is tracking the "snapshot" model? And you're only using the rich model to execute your business logic? I'd build some IOutboxService that would just take the rich model, and create the require domain events. Or you can figure out a way to do it while mapping back to the snapshot model.
@BeHappyAndNice
@BeHappyAndNice Жыл бұрын
@@MilanJovanovicTech Thank you for your response. Yes I am using only my rich model to track the respective business logic and when I want to store any result to the database, I map the rich model to a snapshot model. So, any events that were raised inside of rich model, will be missed by ef core change tracker.
@EHBRod13
@EHBRod13 6 ай бұрын
I use id value objects for my domain entities. So I have something like public sealed class domainEntityName : Entity { ... }. My domainEntityNameId inherits from public sealed class UserId : EntityId { ... }. At min 10:41, where you grab the domain events from the changetracker, would I put something like ChangeTracker.Entries() ? The reason I ask is because when I try to obtain my domain events, I get zero count.
@MilanJovanovicTech
@MilanJovanovicTech 6 ай бұрын
You'd be better off creating an IEntity interface, with the methods to get and clear domain events ChangeTracker.Entries
@EHBRod13
@EHBRod13 6 ай бұрын
@@MilanJovanovicTech Oh, that’s a great idea! Thanks! Your vids have helped me so much
@tiagosantos2136
@tiagosantos2136 4 ай бұрын
Why is domain event publishing being implemented in ApplicationDbContext? Shouldn't this be implemented in UnitOfWork (of course, if you are using the pattern)?
@MilanJovanovicTech
@MilanJovanovicTech 4 ай бұрын
The ApplicationDbContext is the unit of work
@dragannikolic568
@dragannikolic568 Жыл бұрын
Hi Milan, Thx again for nice introduction to domain events! 1. Is implementation of the Application's OrderCreatedEvent.cs: internal record OrderCreatedEvent(Guid Id); or we need something more? 2. May I ask for the name the VS theme that you're using. Very simple and nice one.
@MilanJovanovicTech
@MilanJovanovicTech Жыл бұрын
1) Yes 2) I'm using native VS dark theme + ReSharper syntax highlighting
@dragannikolic568
@dragannikolic568 Жыл бұрын
@@MilanJovanovicTech Thx for answering!!! I'm using VS17.5.5 default dark theme but am not using Resharper. Difference might be there. I have to install some version of Resharper although VS has a lot of builtin features regarding helping in coding already. Thx. again!
@volodymyrliashenko1024
@volodymyrliashenko1024 Жыл бұрын
So..... Everything is possible to implement without MediatR. And it will have exactly the same behavior but without additional framework. Please correct me if I'm wrong.
@MilanJovanovicTech
@MilanJovanovicTech Жыл бұрын
I'm only using MediatR to publish events and trigger the handlers. You can easily solve that without MediatR if you want to
@rohit704
@rohit704 Жыл бұрын
Milan, can we store saga in MS-SQL apart from StoreInPostgres?
@MilanJovanovicTech
@MilanJovanovicTech Жыл бұрын
Yes you can
@adiviuh3693
@adiviuh3693 Жыл бұрын
Hi, Milan. I want to ask you to create a video about Cancellation token. I know what is it, but I'm interesting in situation there I have to implement the cancellation callback for production. This thing possibly the most frequently used element and a lot of developers actually don't understand how to use it. (As am I actually😅). I'm coming to read.
@MilanJovanovicTech
@MilanJovanovicTech Жыл бұрын
Got it!
@jeremyhb1393
@jeremyhb1393 Жыл бұрын
Hii 🖐 I watched your video on creating domain events, and I found it very informative. However, I noticed that your implementation seems to violate the principle that the domain should not depend on any dependencies.
@MilanJovanovicTech
@MilanJovanovicTech Жыл бұрын
Should not depend on other layers
@arquimedesgarcia2632
@arquimedesgarcia2632 6 ай бұрын
Is the code available to download and practice?
@MilanJovanovicTech
@MilanJovanovicTech 6 ай бұрын
I share the code on Patreon
@ronaldschutte7948
@ronaldschutte7948 5 ай бұрын
Why not only trigger the event when a save was succesfull? Then you would only communicate the persistant state.
@MilanJovanovicTech
@MilanJovanovicTech 5 ай бұрын
It's not atomic
@ronaldschutte7948
@ronaldschutte7948 5 ай бұрын
@@MilanJovanovicTech I understand. I kind of thought about this like strong vs eventual consistancy. When you only communicate what was saved, then you are sure that what you communicate is the same as the persistant state.
@husseinhajmohammed3812
@husseinhajmohammed3812 Жыл бұрын
what if i have domain events that change state of entities how this changes will save in database ? i think can solve this : await base.SaveChngesAsync(); // publish events await base.SaveChangesAsync();
@MilanJovanovicTech
@MilanJovanovicTech Жыл бұрын
With the Outbox pattern, coming up :)
@haroldpepete
@haroldpepete Жыл бұрын
like Homer would say, yesssss but nottt, it didn't like what i saw, why do you use context database and you don't create a repository o service to use data layer, you have datacontext on each handler, ummmm it looks bad
@MilanJovanovicTech
@MilanJovanovicTech Жыл бұрын
You can extrapolate your own implementation from the example, that's good enough for me
The Beginner's Guide to Clean Architecture
13:19
Milan Jovanović
Рет қаралды 22 М.
How To Create Smart Enums in C# With Rich Behavior
17:31
Milan Jovanović
Рет қаралды 53 М.
小丑把天使丢游泳池里#short #angel #clown
00:15
Super Beauty team
Рет қаралды 30 МЛН
Sunglasses Didn't Cover For Me! 🫢
00:12
Polar Reacts
Рет қаралды 5 МЛН
Can A Seed Grow In Your Nose? 🤔
00:33
Zack D. Films
Рет қаралды 32 МЛН
You DON'T want an In-Memory Event Bus like MediatR
11:20
CodeOpinion
Рет қаралды 22 М.
Vertical Slice Architecture Project Setup From Scratch
22:43
Milan Jovanović
Рет қаралды 55 М.
I Built a Neural Network in C# From Scratch. Here’s What I Learned…
18:12
This is the Only Right Way to Write React clean-code - SOLID
18:23
Implementing the Transactional Outbox pattern with Hangfire
14:28
Milan Jovanović
Рет қаралды 10 М.
Should you publish Domain Events or Integration Events?
10:44
CodeOpinion
Рет қаралды 15 М.
Writing My Own Database From Scratch
42:00
Tony Saro
Рет қаралды 203 М.
Слетела прошивка на LiXiang L7
1:01
Настя ЧПЕК Туман
Рет қаралды 3,4 МЛН
Nokia 3310 top
0:20
YT 𝒯𝒾𝓂𝓉𝒾𝓀
Рет қаралды 5 МЛН
Как настроить камеру хоп-ап
1:00
TimToker
Рет қаралды 1,3 МЛН
Что делать если в телефон попала вода?
0:17
Лена Тропоцел
Рет қаралды 4,4 МЛН