SlideShare a Scribd company logo
1 of 85
Download to read offline
Domain Events
Czyli jak radzić sobie z rzeczywistością!
Mateusz Stasch | 2016.04.11
Mateusz Stasch
@mattstasch
http://mattstasch.net
?
Domain Events
Domain Events
UI
Events
Event Loop
…
Application
Events
EDA
…
…
Domain
Events
UI
Events
Event Loop
…
Application
Events
EDA
…
…
Domain
Events
Domain event is something that happened
that domain experts care about.
Anonymous
Domain(T0) Domain(T1)
Operation
E
NOW
C D E
H
C D E
H1 H2
C D E
H1 H2
Ext. System
C D E
H1 H2
Ext. System
Sync
Async
public void RegisterCardPayment(EntityId id, CardPayment paymentDetails)
{
// Validation...
var caseToBePaid = _caseDao.GetById(id);
// It was not so simple... ;)
caseToBePaid.Payments.Add(paymentDetails);
caseToBePaid.RefreshOutstandingBalance();
_mmeGateway.RegisterPayment(/*...*/);
if (paymentDetails.CardType == CardType.Credit)
{
// Message generation...
_mailGateway.Send(/*...*/);
}
/* Send to PDA... */
}
Business Logic PDA MME Mail
Business Logic PDA MME Mail
Test Scope
Business Logic PDA MME Mail
CBL * CPDA
CMME CMail* *
Test Scope
public void RegisterCardPayment(EntityId id, CardPayment paymentDetails)
{
// Validation...
var caseToBePaid = _caseDao.GetById(id);
// It was not so simple... ;)
caseToBePaid.Payments.Add(paymentDetails);
caseToBePaid.RefreshOutstandingBalance();
_mmeGateway.RegisterPayment(/*...*/);
if (paymentDetails.CardType == CardType.Credit)
{
// Message generation...
_mailGateway.Send(/*...*/);
}
/* Send to PDA... */
}
public void RegisterCardPayment(EntityId id,
CardPayment paymentDetails)
{
// Validation...
var caseToBePaid = _caseDao.GetById(id);
// It was not so simple... ;)
caseToBePaid.Payments.Add(paymentDetails);
caseToBePaid.RefreshOutstandingBalance();
_eventBus.Raise(new CardPaymentRegisteredEvent
{
Id = id,
Details = paymentDetails
});
}
public class CardPaymentRegisteredEvent : Event
{
public CardPayment Details { get; set; }
}
Business Logic PDA MME Mail
public class MmePaymentsHandler
: IEventHandler<CardPaymentRegisteredEvent>
{
private MMEGateway _mmeGateway;
/* ctor(MMEGateway Gateway)... */
public void Handle(CardPaymentRegisteredEvent @event)
{
if (@event.Details.CardType == CardType.Credit)
{
_mmeGateway.Send(/*...*/);
}
}
}
public class MmePaymentsHandler
: IEventHandler<CardPaymentRegisteredEvent>
{
private MMEGateway _mmeGateway;
/* ctor(MMEGateway Gateway)... */
public void Handle(CardPaymentRegisteredEvent @event)
{
if (@event.Details.CardType == CardType.Credit)
{
_mmeGateway.Send(/*...*/);
}
}
}
Event Bus
Listen
Business Logic
Publish
Listen
PDA
MME
Listen
Mail
Event Bus
Listen
Business Logic
Publish
Listen
PDA
MME
Listen
Mail
Event Bus
Listen
Business Logic
Publish
Listen
PDA
MME
Listen
Mail
CBL + CPDA + CMME + CMail
public class MmePaymentsHandler
: IEventHandler<CardPaymentRegisteredEvent>
{
private MMEGateway _mmeGateway;
/* ctor(MMEGateway Gateway)... */
public void Handle(CardPaymentRegisteredEvent @event)
{
if (@event.Details.CardType == CardType.Credit)
{
_mmeGateway.Send(/*...*/);
}
}
}
Event Bus
Listen
Business Logic
Publish
Listen
PDA
MME
Listen
Mail
Listen
…
Listen
…
Nie wiem ilu Was jest, kiedy i w
jakiej kolejności wykonacie
pracę oraz jaki będzie jej wynik
SendEmailEvent
#1
SendEmailEvent
Życzenie, nie fakt!
#1
NOW
#1
PaymentRejectedEvent
Zrób coś, bo Payment został odrzucony!
#1
Czas przeszły,
tryb dokonany!
#1
Fakt, a nie życzenie!
#1
_eventBus.Raise(new CardPaymentRegisteredEvent
{
Id = id,
Details = paymentDetails,
Case = caseToBePaid
});
#2
_eventBus.Raise(new CardPaymentRegisteredEvent
{
Id = id,
Details = paymentDetails,
Case = caseToBePaid
});
#2
Zdarzenie powinno
być małe* i serializowalne
#2
2
1
#3
public void RegisterCardPayment(EntityId id,
CardPayment paymentDetails)
{
var caseToBePaid = _caseDao.GetById(id);
caseToBePaid.Payments.Add(paymentDetails);
caseToBePaid.RefreshOutstandingBalance();
if (caseToBePaid.OutstandingBalance.IsZero)
{
caseToBePaid.MarkAsPaid();
}
/* MME */
/* Mail */
/* Send to PDA... */
}
public void RegisterCardPayment(EntityId id,
CardPayment paymentDetails)
{
var caseToBePaid = _caseDao.GetById(id);
caseToBePaid.Payments.Add(paymentDetails);
caseToBePaid.RefreshOutstandingBalance();
if (caseToBePaid.OutstandingBalance.IsZero)
{
caseToBePaid.MarkAsPaid();
}
/* MME */
/* Mail */
/* Send to PDA... */
}
Nie wiem ilu Was jest, kiedy i w
jakiej kolejności wykonacie
pracę oraz jaki będzie jej wynik
#3
Nie polegaj na
konkretnej
implementacji!
Infrastruktury zdarzeń.
#3
public void RegisterCardPayment(EntityId id,
CardPayment paymentDetails)
{
var caseToBePaid = _caseDao.GetById(id);
// It was not so simple... ;)
caseToBePaid.Payments.Add(paymentDetails);
caseToBePaid.RefreshOutstandingBalance();
if (caseToBePaid.OutstandingBalance.IsZero)
{
_eventBus.Raise(new CasePaidEvent { Id = id });
}
_eventBus.Raise(new CardPaymentRegisteredEvent
{
Id = id,
Details = paymentDetails
});
}
public void RegisterCashPayment(EntityId id /*...*/)
public void RegisterCardPayment(EntityId id,
CardPayment paymentDetails)
{
var caseToBePaid = _caseDao.GetById(id);
// It was not so simple... ;)
caseToBePaid.Payments.Add(paymentDetails);
caseToBePaid.RefreshOutstandingBalance();
if (caseToBePaid.OutstandingBalance.IsZero)
{
_eventBus.Raise(new CasePaidEvent { Id = id });
}
_eventBus.Raise(new CardPaymentRegisteredEvent
{
Id = id,
Details = paymentDetails
});
}
public void RegisterCashPayment(EntityId id /*...*/)
public void RegisterCardPayment(EntityId id,
CardPayment paymentDetails)
{
var caseToBePaid = _caseDao.GetById(id);
// It was not so simple... ;)
caseToBePaid.Payments.Add(paymentDetails);
caseToBePaid.RefreshOutstandingBalance();
if (caseToBePaid.OutstandingBalance.IsZero)
{
_eventBus.Raise(new CasePaidEvent { Id = id });
}
_eventBus.Raise(new CardPaymentRegisteredEvent
{
Id = id,
Details = paymentDetails
});
}
public void RegisterCashPayment(EntityId id /*...*/)
public void RegisterCardPayment(EntityId id,
CardPayment paymentDetails)
{
var caseToBePaid = _caseDao.GetById(id);
// It was not so simple... ;)
caseToBePaid.Payments.Add(paymentDetails);
caseToBePaid.RefreshOutstandingBalance();
if (caseToBePaid.OutstandingBalance.IsZero)
{
_eventBus.Raise(new CasePaidEvent { Id = id });
}
_eventBus.Raise(new CardPaymentRegisteredEvent
{
Id = id,
Details = paymentDetails
});
}
public void RegisterCashPayment(EntityId id /*...*/)
Utrata kontroli
public void RegisterCardPayment(EntityId id,
CardPayment paymentDetails)
{
var caseToBePaid = _caseDao.GetById(id);
// It was not so simple... ;)
caseToBePaid.Payments.Add(paymentDetails);
caseToBePaid.RefreshOutstandingBalance();
_eventBus.Raise(new CardPaymentRegisteredEvent
{
Id = id,
Details = paymentDetails
});
}
public void RegisterCashPayment(EntityId id /*...*/)
Jedno zdarzenie ma
jedno źródło!
#4
public void AddGood(EntityId id, Good good)
{
var @case = _caseDao.GetById(id);
@case.AddGood(good);
_mmeGateway.Send(/*...*/ @case.Balance);
/* Other stuff */
}
#5
public void AddGood(EntityId id, Good good)
{
var @case = _caseDao.GetById(id);
@case.AddGood(good);
_mmeGateway.Send(/*...*/ @case.Balance);
/* Other stuff */
}
#5
#5public class GoodAddedEvent : IEvent
{
public EntityId Id { get; set; }
public DateTimeOffset RaisedAt { get; set; }
public Good Good { get; set; }
public Money Balance { get; set; }
}
#5public class GoodAddedEvent : IEvent
{
public EntityId Id { get; set; }
public DateTimeOffset RaisedAt { get; set; }
public Good Good { get; set; }
public Money Balance { get; set; }
}
public void AddGood(EntityId id, Good good)
{
var @case = _caseDao.GetById(id);
@case.AddGood(good);
/* Raise Event */
_mailGateway.Send(/*...*/ @case.OutstandingBalance);
/* Other stuff */
}
#5
#5
Nie modeluj zdarzenia dla
konkretnego handlera
ReCap
• Fakt, a nie życzenie!
• Obiekt zdarzenia powinien być mały
• Nie polegaj na skutkach ubocznych swojej
implementacji
• Jedno zdarzenie ma jedno źródło
• Nie modeluj zdarzenia dla jednego handlera
• Nie używajcie EF-a.
Jaką logikę, przerzucić
do handlera?
Refactoring
 Powiadomienia(Maile, SMSy)
 Integracje z zew. systemami
o ile nie są krytyczne*
 Eager Data Derivation
 Generowanie dokumentów/raportów
 Unieważnianie :D Cache
MVP
Niestety na przykładzie EF-a
public interface IEvent
{
int Id { get; set; }
Type EntityType { get; set; }
}
public interface IEventHandler<TEvent>
where TEvent : IEvent
{
void Handle(TEvent @event);
}
public interface IEventSource
{
IList<IEvent> Events { get; }
}
this.Raise(new CasePaidEvent() {Id = id});
private void ApplyEvents()
{
var processed = new List<IEvent>();
for (;;)
{
var events = ChangeTracker.Entries<IEventSource>()
.SelectMany(x => x.Entity.Events)
.Except(processed)
.ToList();
if (!events.Any()) break;
foreach (var @event in events)
{
_eventDispatcher.Apply(@event);
processed.Add(@event);
}
}
}
public override int SaveChanges() {
ApplyEvents();
base.SaveChanges();
}
private void ApplyEvents()
{
var processed = new List<IEvent>();
for (;;)
{
var events = ChangeTracker.Entries<IEventSource>()
.SelectMany(x => x.Entity.Events)
.Except(processed)
.ToList();
if (!events.Any()) break;
foreach (var @event in events)
{
_eventDispatcher.Apply(@event);
processed.Add(@event);
}
}
}
public override int SaveChanges() {
ApplyEvents();
base.SaveChanges();
}
private void ApplyEvents()
{
var processed = new List<IEvent>();
for (;;)
{
var events = ChangeTracker.Entries<IEventSource>()
.SelectMany(x => x.Entity.Events)
.Except(processed)
.ToList();
if (!events.Any()) break;
foreach (var @event in events)
{
_eventDispatcher.Apply(@event);
processed.Add(@event);
}
}
}
public override int SaveChanges() {
ApplyEvents();
base.SaveChanges();
}
private void ApplyEvents()
{
var processed = new List<IEvent>();
for (;;)
{
var events = ChangeTracker.Entries<IEventSource>()
.SelectMany(x => x.Entity.Events)
.Except(processed)
.ToList();
if (!events.Any()) break;
foreach (var @event in events)
{
_eventDispatcher.Apply(@event);
processed.Add(@event);
}
}
}
public override int SaveChanges() {
ApplyEvents();
base.SaveChanges();
}
private void ApplyEvents()
{
var processed = new List<IEvent>();
for (;;)
{
var events = ChangeTracker.Entries<IEventSource>()
.SelectMany(x => x.Entity.Events)
.Except(processed)
.ToList();
if (!events.Any()) break;
foreach (var @event in events)
{
_eventDispatcher.Apply(@event);
processed.Add(@event);
}
}
}
public override int SaveChanges() {
ApplyEvents();
base.SaveChanges();
}
public class EventDispatcher : IEventDispatcher
{
/*...*/
public void Apply(IEvent @event)
{
// ... Call generic ApplyTyped
}
protected void ApplyTyped<TEvent>(TEvent @event)
where TEvent : IEvent
{
var handlers = _scope.Resolve<IEnumerable<IEventHandler<TEvent>>>();
foreach (var eventHandler in handlers)
{
eventHandler.Handle(@event);
}
}
}
public class EventDispatcher : IEventDispatcher
{
/*...*/
public void Apply(IEvent @event)
{
// ... Call generic ApplyTyped
}
protected void ApplyTyped<TEvent>(TEvent @event)
where TEvent : IEvent
{
var handlers = _scope.Resolve<IEnumerable<IEventHandler<TEvent>>>();
foreach (var eventHandler in handlers)
{
eventHandler.Handle(@event);
}
}
}
public void Apply(IEvent @event)
{
try
{
applyTypedMethod.MakeGenericMethod(@event.GetType())
.Invoke(this, new object[] { @event });
}
catch (TargetInvocationException ex)
{
ex.InnerException.PreserveStackTrace();
throw ex.InnerException;
}
}
public class AgreementSubmitted : IEvent
{
public DateTime EffectiveDate { get; set; }
public string Note { get; set; }
public int Id { get; set; }
public Type EntityType { get; set; }
public AgreementSubmitted(int id,
DateTime effectiveDate,
string note)
{
Id = id;
EffectiveDate = effectiveDate;
Note = note;
}
}
public void Handle(AgreementSubmitted @event)
{
SendEmail(ApprovalRequestEmailCode,
@event.Id, pa => pa.Administrators);
}
Event Log jako Log
Historia pewnego włamania...
public class EventPersister<TEvent> : IEventHandler<TEvent>
where TEvent : IEvent
{
private readonly IEventStore _eventStore;
public void Handle(TEvent @event)
{
_eventStore.Save(new EventEnvelope<TEvent>(@event));
}
}
SELECT * FROM EventLog
WHERE
EntityType = 'NS.Case'
AND Id = 302049
ORDER BY RaisedAt
Id EntityType RaisedAt RaisedBy EventType Content
302049 Domain.Case 2016-01-01 20:54:43.104 56 Events.Case.Created {…}
302049 Domain.Case 2016-01-01 20:55:43.105 56 Events.Case.CardPaymentRegistered {…}
302049 Domain.Case 2016-03-01 15:01:13.554 76 Events.Case.GoodsCollected {…}
302049 Domain.Case 2016-03-01 15:01:13.555 1 Events.Case.Paid {}
302050 Domain.Case 2016-03-01 15:01:13.556 1 Events.Case.Closed {}
SELECT * FROM EventLog
WHERE
EntityType = 'NS.Case'
AND Id = 302049
ORDER BY RaisedAt
Id EntityType RaisedAt RaisedBy EventType Content
302049 Domain.Case 2016-01-01 20:54:43.104 56 Events.Case.Created {…}
302049 Domain.Case 2016-01-01 20:55:43.105 56 Events.Case.CardPaymentRegistered {…}
302049 Domain.Case 2016-03-01 15:01:13.554 76 Events.Case.GoodsCollected {…}
302049 Domain.Case 2016-03-01 15:01:13.555 1 Events.Case.Paid {}
302050 Domain.Case 2016-03-01 15:01:13.556 1 Events.Case.Closed {}
Event Sourcing
Replay
Entity(TN)
Event Storming
Pytania?
Dzięki!
Domain Events
Czyli jak radzić sobie z rzeczywistością!
Mateusz Stasch | 2016.04.11

More Related Content

Viewers also liked

4Developers: Łukasz Łysik- Message-driven architecture with RabbitMQ
4Developers: Łukasz Łysik- Message-driven architecture with RabbitMQ4Developers: Łukasz Łysik- Message-driven architecture with RabbitMQ
4Developers: Łukasz Łysik- Message-driven architecture with RabbitMQPROIDEA
 
4Developers: Norbert Wójtowicz- Data-Oriented Architecture
4Developers: Norbert Wójtowicz- Data-Oriented Architecture4Developers: Norbert Wójtowicz- Data-Oriented Architecture
4Developers: Norbert Wójtowicz- Data-Oriented ArchitecturePROIDEA
 
Net core (dawniej 5.0) – co to dla mnie. też dużo o open source
Net core (dawniej   5.0) – co to dla mnie. też dużo o open sourceNet core (dawniej   5.0) – co to dla mnie. też dużo o open source
Net core (dawniej 5.0) – co to dla mnie. też dużo o open sourceTomasz Kopacz
 
PLNOG 18 - Alan Kuczewski - "Mały może więcej" - Rozwiązanie wysokiej dostępn...
PLNOG 18 - Alan Kuczewski - "Mały może więcej" - Rozwiązanie wysokiej dostępn...PLNOG 18 - Alan Kuczewski - "Mały może więcej" - Rozwiązanie wysokiej dostępn...
PLNOG 18 - Alan Kuczewski - "Mały może więcej" - Rozwiązanie wysokiej dostępn...PROIDEA
 
PLNOG 18 - Marcin Kuczera- ONT idealny
PLNOG 18 - Marcin Kuczera- ONT idealny PLNOG 18 - Marcin Kuczera- ONT idealny
PLNOG 18 - Marcin Kuczera- ONT idealny PROIDEA
 
4Developers: Krzysztof Staruch, Kamil Piechociak- Pracuj.pl - SOA zrobione (p...
4Developers: Krzysztof Staruch, Kamil Piechociak- Pracuj.pl - SOA zrobione (p...4Developers: Krzysztof Staruch, Kamil Piechociak- Pracuj.pl - SOA zrobione (p...
4Developers: Krzysztof Staruch, Kamil Piechociak- Pracuj.pl - SOA zrobione (p...PROIDEA
 
4Developers: Aplikacja od SaaSa do IdaaSa
4Developers: Aplikacja od SaaSa do IdaaSa4Developers: Aplikacja od SaaSa do IdaaSa
4Developers: Aplikacja od SaaSa do IdaaSaTomek Onyszko
 
4Developers: Marcin Iwanowski- WinDbg, gdy Visual Studio to za mało...
4Developers: Marcin Iwanowski- WinDbg, gdy Visual Studio to za mało...4Developers: Marcin Iwanowski- WinDbg, gdy Visual Studio to za mało...
4Developers: Marcin Iwanowski- WinDbg, gdy Visual Studio to za mało...PROIDEA
 

Viewers also liked (8)

4Developers: Łukasz Łysik- Message-driven architecture with RabbitMQ
4Developers: Łukasz Łysik- Message-driven architecture with RabbitMQ4Developers: Łukasz Łysik- Message-driven architecture with RabbitMQ
4Developers: Łukasz Łysik- Message-driven architecture with RabbitMQ
 
4Developers: Norbert Wójtowicz- Data-Oriented Architecture
4Developers: Norbert Wójtowicz- Data-Oriented Architecture4Developers: Norbert Wójtowicz- Data-Oriented Architecture
4Developers: Norbert Wójtowicz- Data-Oriented Architecture
 
Net core (dawniej 5.0) – co to dla mnie. też dużo o open source
Net core (dawniej   5.0) – co to dla mnie. też dużo o open sourceNet core (dawniej   5.0) – co to dla mnie. też dużo o open source
Net core (dawniej 5.0) – co to dla mnie. też dużo o open source
 
PLNOG 18 - Alan Kuczewski - "Mały może więcej" - Rozwiązanie wysokiej dostępn...
PLNOG 18 - Alan Kuczewski - "Mały może więcej" - Rozwiązanie wysokiej dostępn...PLNOG 18 - Alan Kuczewski - "Mały może więcej" - Rozwiązanie wysokiej dostępn...
PLNOG 18 - Alan Kuczewski - "Mały może więcej" - Rozwiązanie wysokiej dostępn...
 
PLNOG 18 - Marcin Kuczera- ONT idealny
PLNOG 18 - Marcin Kuczera- ONT idealny PLNOG 18 - Marcin Kuczera- ONT idealny
PLNOG 18 - Marcin Kuczera- ONT idealny
 
4Developers: Krzysztof Staruch, Kamil Piechociak- Pracuj.pl - SOA zrobione (p...
4Developers: Krzysztof Staruch, Kamil Piechociak- Pracuj.pl - SOA zrobione (p...4Developers: Krzysztof Staruch, Kamil Piechociak- Pracuj.pl - SOA zrobione (p...
4Developers: Krzysztof Staruch, Kamil Piechociak- Pracuj.pl - SOA zrobione (p...
 
4Developers: Aplikacja od SaaSa do IdaaSa
4Developers: Aplikacja od SaaSa do IdaaSa4Developers: Aplikacja od SaaSa do IdaaSa
4Developers: Aplikacja od SaaSa do IdaaSa
 
4Developers: Marcin Iwanowski- WinDbg, gdy Visual Studio to za mało...
4Developers: Marcin Iwanowski- WinDbg, gdy Visual Studio to za mało...4Developers: Marcin Iwanowski- WinDbg, gdy Visual Studio to za mało...
4Developers: Marcin Iwanowski- WinDbg, gdy Visual Studio to za mało...
 

Similar to 4Developers: Mateusz Stasch- Domain Events - czyli jak radzić sobie z rzeczywistością

June2013 Meetup : In-App Billing by Soham & Senthil
June2013 Meetup : In-App Billing by Soham & SenthilJune2013 Meetup : In-App Billing by Soham & Senthil
June2013 Meetup : In-App Billing by Soham & SenthilBlrDroid
 
Barcelona Developers Conference 2011
Barcelona Developers Conference 2011Barcelona Developers Conference 2011
Barcelona Developers Conference 2011PayPal
 
Change to oop formatimport java.util.Scanner;import java.io.;.pdf
Change to oop formatimport java.util.Scanner;import java.io.;.pdfChange to oop formatimport java.util.Scanner;import java.io.;.pdf
Change to oop formatimport java.util.Scanner;import java.io.;.pdfMAYANKBANSAL1981
 
Serverless Functions and Vue.js
Serverless Functions and Vue.jsServerless Functions and Vue.js
Serverless Functions and Vue.jsSarah Drasner
 
Supersize me
Supersize meSupersize me
Supersize medominion
 
GigaSpaces XAP - Don't Call Me Cache!
GigaSpaces XAP - Don't Call Me Cache!GigaSpaces XAP - Don't Call Me Cache!
GigaSpaces XAP - Don't Call Me Cache!Uri Cohen
 
I need help creating a basic and simple Java program. Here is the ex.pdf
I need help creating a basic and simple Java program. Here is the ex.pdfI need help creating a basic and simple Java program. Here is the ex.pdf
I need help creating a basic and simple Java program. Here is the ex.pdfrajeshjangid1865
 
Business News, Personal Finance and Money News
Business News, Personal Finance and Money NewsBusiness News, Personal Finance and Money News
Business News, Personal Finance and Money Newsmoaninglunatic320
 
Tony Vitabile .Net Portfolio
Tony Vitabile .Net PortfolioTony Vitabile .Net Portfolio
Tony Vitabile .Net Portfoliovitabile
 
Project: Call Center Management
Project: Call Center ManagementProject: Call Center Management
Project: Call Center Managementpritamkumar
 
Dont call me cache java version
Dont call me cache java versionDont call me cache java version
Dont call me cache java versionAvisi B.V.
 
jQuery : Events are where it happens!
jQuery : Events are where it happens!jQuery : Events are where it happens!
jQuery : Events are where it happens!Wildan Maulana
 
Business News, Personal Finance and Money News
Business News, Personal Finance and Money NewsBusiness News, Personal Finance and Money News
Business News, Personal Finance and Money Newseminentoomph4388
 
Dont call me cache april 17
Dont call me cache april 17Dont call me cache april 17
Dont call me cache april 17Nati Shalom
 
Data Mining Open Ap Is
Data Mining Open Ap IsData Mining Open Ap Is
Data Mining Open Ap Isoscon2007
 
Piggibacking Platform Events, Igor Chtivelband
Piggibacking Platform Events, Igor ChtivelbandPiggibacking Platform Events, Igor Chtivelband
Piggibacking Platform Events, Igor ChtivelbandCzechDreamin
 
IndexedDB and Push Notifications in Progressive Web Apps
IndexedDB and Push Notifications in Progressive Web AppsIndexedDB and Push Notifications in Progressive Web Apps
IndexedDB and Push Notifications in Progressive Web AppsAdégòkè Obasá
 

Similar to 4Developers: Mateusz Stasch- Domain Events - czyli jak radzić sobie z rzeczywistością (20)

June2013 Meetup : In-App Billing by Soham & Senthil
June2013 Meetup : In-App Billing by Soham & SenthilJune2013 Meetup : In-App Billing by Soham & Senthil
June2013 Meetup : In-App Billing by Soham & Senthil
 
Barcelona Developers Conference 2011
Barcelona Developers Conference 2011Barcelona Developers Conference 2011
Barcelona Developers Conference 2011
 
Apex Design Patterns
Apex Design PatternsApex Design Patterns
Apex Design Patterns
 
Change to oop formatimport java.util.Scanner;import java.io.;.pdf
Change to oop formatimport java.util.Scanner;import java.io.;.pdfChange to oop formatimport java.util.Scanner;import java.io.;.pdf
Change to oop formatimport java.util.Scanner;import java.io.;.pdf
 
Serverless Functions and Vue.js
Serverless Functions and Vue.jsServerless Functions and Vue.js
Serverless Functions and Vue.js
 
Supersize me
Supersize meSupersize me
Supersize me
 
GigaSpaces XAP - Don't Call Me Cache!
GigaSpaces XAP - Don't Call Me Cache!GigaSpaces XAP - Don't Call Me Cache!
GigaSpaces XAP - Don't Call Me Cache!
 
I need help creating a basic and simple Java program. Here is the ex.pdf
I need help creating a basic and simple Java program. Here is the ex.pdfI need help creating a basic and simple Java program. Here is the ex.pdf
I need help creating a basic and simple Java program. Here is the ex.pdf
 
Business News, Personal Finance and Money News
Business News, Personal Finance and Money NewsBusiness News, Personal Finance and Money News
Business News, Personal Finance and Money News
 
Tony Vitabile .Net Portfolio
Tony Vitabile .Net PortfolioTony Vitabile .Net Portfolio
Tony Vitabile .Net Portfolio
 
Project: Call Center Management
Project: Call Center ManagementProject: Call Center Management
Project: Call Center Management
 
Dont call me cache java version
Dont call me cache java versionDont call me cache java version
Dont call me cache java version
 
Domain Driven Design
Domain Driven DesignDomain Driven Design
Domain Driven Design
 
jQuery : Events are where it happens!
jQuery : Events are where it happens!jQuery : Events are where it happens!
jQuery : Events are where it happens!
 
Business News, Personal Finance and Money News
Business News, Personal Finance and Money NewsBusiness News, Personal Finance and Money News
Business News, Personal Finance and Money News
 
Dont call me cache april 17
Dont call me cache april 17Dont call me cache april 17
Dont call me cache april 17
 
Opensocial Codelab
Opensocial CodelabOpensocial Codelab
Opensocial Codelab
 
Data Mining Open Ap Is
Data Mining Open Ap IsData Mining Open Ap Is
Data Mining Open Ap Is
 
Piggibacking Platform Events, Igor Chtivelband
Piggibacking Platform Events, Igor ChtivelbandPiggibacking Platform Events, Igor Chtivelband
Piggibacking Platform Events, Igor Chtivelband
 
IndexedDB and Push Notifications in Progressive Web Apps
IndexedDB and Push Notifications in Progressive Web AppsIndexedDB and Push Notifications in Progressive Web Apps
IndexedDB and Push Notifications in Progressive Web Apps
 

Recently uploaded

Gen AI in Business - Global Trends Report 2024.pdf
Gen AI in Business - Global Trends Report 2024.pdfGen AI in Business - Global Trends Report 2024.pdf
Gen AI in Business - Global Trends Report 2024.pdfAddepto
 
Human Factors of XR: Using Human Factors to Design XR Systems
Human Factors of XR: Using Human Factors to Design XR SystemsHuman Factors of XR: Using Human Factors to Design XR Systems
Human Factors of XR: Using Human Factors to Design XR SystemsMark Billinghurst
 
Pigging Solutions in Pet Food Manufacturing
Pigging Solutions in Pet Food ManufacturingPigging Solutions in Pet Food Manufacturing
Pigging Solutions in Pet Food ManufacturingPigging Solutions
 
Scanning the Internet for External Cloud Exposures via SSL Certs
Scanning the Internet for External Cloud Exposures via SSL CertsScanning the Internet for External Cloud Exposures via SSL Certs
Scanning the Internet for External Cloud Exposures via SSL CertsRizwan Syed
 
Install Stable Diffusion in windows machine
Install Stable Diffusion in windows machineInstall Stable Diffusion in windows machine
Install Stable Diffusion in windows machinePadma Pradeep
 
WordPress Websites for Engineers: Elevate Your Brand
WordPress Websites for Engineers: Elevate Your BrandWordPress Websites for Engineers: Elevate Your Brand
WordPress Websites for Engineers: Elevate Your Brandgvaughan
 
Science&tech:THE INFORMATION AGE STS.pdf
Science&tech:THE INFORMATION AGE STS.pdfScience&tech:THE INFORMATION AGE STS.pdf
Science&tech:THE INFORMATION AGE STS.pdfjimielynbastida
 
Pigging Solutions Piggable Sweeping Elbows
Pigging Solutions Piggable Sweeping ElbowsPigging Solutions Piggable Sweeping Elbows
Pigging Solutions Piggable Sweeping ElbowsPigging Solutions
 
costume and set research powerpoint presentation
costume and set research powerpoint presentationcostume and set research powerpoint presentation
costume and set research powerpoint presentationphoebematthew05
 
Benefits Of Flutter Compared To Other Frameworks
Benefits Of Flutter Compared To Other FrameworksBenefits Of Flutter Compared To Other Frameworks
Benefits Of Flutter Compared To Other FrameworksSoftradix Technologies
 
Designing IA for AI - Information Architecture Conference 2024
Designing IA for AI - Information Architecture Conference 2024Designing IA for AI - Information Architecture Conference 2024
Designing IA for AI - Information Architecture Conference 2024Enterprise Knowledge
 
"LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks...
"LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks..."LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks...
"LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks...Fwdays
 
Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...
Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...
Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...shyamraj55
 
Understanding the Laravel MVC Architecture
Understanding the Laravel MVC ArchitectureUnderstanding the Laravel MVC Architecture
Understanding the Laravel MVC ArchitecturePixlogix Infotech
 
Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!Commit University
 
Unblocking The Main Thread Solving ANRs and Frozen Frames
Unblocking The Main Thread Solving ANRs and Frozen FramesUnblocking The Main Thread Solving ANRs and Frozen Frames
Unblocking The Main Thread Solving ANRs and Frozen FramesSinan KOZAK
 
My INSURER PTE LTD - Insurtech Innovation Award 2024
My INSURER PTE LTD - Insurtech Innovation Award 2024My INSURER PTE LTD - Insurtech Innovation Award 2024
My INSURER PTE LTD - Insurtech Innovation Award 2024The Digital Insurer
 

Recently uploaded (20)

Gen AI in Business - Global Trends Report 2024.pdf
Gen AI in Business - Global Trends Report 2024.pdfGen AI in Business - Global Trends Report 2024.pdf
Gen AI in Business - Global Trends Report 2024.pdf
 
Human Factors of XR: Using Human Factors to Design XR Systems
Human Factors of XR: Using Human Factors to Design XR SystemsHuman Factors of XR: Using Human Factors to Design XR Systems
Human Factors of XR: Using Human Factors to Design XR Systems
 
Pigging Solutions in Pet Food Manufacturing
Pigging Solutions in Pet Food ManufacturingPigging Solutions in Pet Food Manufacturing
Pigging Solutions in Pet Food Manufacturing
 
Scanning the Internet for External Cloud Exposures via SSL Certs
Scanning the Internet for External Cloud Exposures via SSL CertsScanning the Internet for External Cloud Exposures via SSL Certs
Scanning the Internet for External Cloud Exposures via SSL Certs
 
Install Stable Diffusion in windows machine
Install Stable Diffusion in windows machineInstall Stable Diffusion in windows machine
Install Stable Diffusion in windows machine
 
WordPress Websites for Engineers: Elevate Your Brand
WordPress Websites for Engineers: Elevate Your BrandWordPress Websites for Engineers: Elevate Your Brand
WordPress Websites for Engineers: Elevate Your Brand
 
Science&tech:THE INFORMATION AGE STS.pdf
Science&tech:THE INFORMATION AGE STS.pdfScience&tech:THE INFORMATION AGE STS.pdf
Science&tech:THE INFORMATION AGE STS.pdf
 
Pigging Solutions Piggable Sweeping Elbows
Pigging Solutions Piggable Sweeping ElbowsPigging Solutions Piggable Sweeping Elbows
Pigging Solutions Piggable Sweeping Elbows
 
costume and set research powerpoint presentation
costume and set research powerpoint presentationcostume and set research powerpoint presentation
costume and set research powerpoint presentation
 
Benefits Of Flutter Compared To Other Frameworks
Benefits Of Flutter Compared To Other FrameworksBenefits Of Flutter Compared To Other Frameworks
Benefits Of Flutter Compared To Other Frameworks
 
E-Vehicle_Hacking_by_Parul Sharma_null_owasp.pptx
E-Vehicle_Hacking_by_Parul Sharma_null_owasp.pptxE-Vehicle_Hacking_by_Parul Sharma_null_owasp.pptx
E-Vehicle_Hacking_by_Parul Sharma_null_owasp.pptx
 
Designing IA for AI - Information Architecture Conference 2024
Designing IA for AI - Information Architecture Conference 2024Designing IA for AI - Information Architecture Conference 2024
Designing IA for AI - Information Architecture Conference 2024
 
"LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks...
"LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks..."LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks...
"LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks...
 
Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...
Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...
Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...
 
Vulnerability_Management_GRC_by Sohang Sengupta.pptx
Vulnerability_Management_GRC_by Sohang Sengupta.pptxVulnerability_Management_GRC_by Sohang Sengupta.pptx
Vulnerability_Management_GRC_by Sohang Sengupta.pptx
 
Understanding the Laravel MVC Architecture
Understanding the Laravel MVC ArchitectureUnderstanding the Laravel MVC Architecture
Understanding the Laravel MVC Architecture
 
Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!
 
Unblocking The Main Thread Solving ANRs and Frozen Frames
Unblocking The Main Thread Solving ANRs and Frozen FramesUnblocking The Main Thread Solving ANRs and Frozen Frames
Unblocking The Main Thread Solving ANRs and Frozen Frames
 
DMCC Future of Trade Web3 - Special Edition
DMCC Future of Trade Web3 - Special EditionDMCC Future of Trade Web3 - Special Edition
DMCC Future of Trade Web3 - Special Edition
 
My INSURER PTE LTD - Insurtech Innovation Award 2024
My INSURER PTE LTD - Insurtech Innovation Award 2024My INSURER PTE LTD - Insurtech Innovation Award 2024
My INSURER PTE LTD - Insurtech Innovation Award 2024
 

4Developers: Mateusz Stasch- Domain Events - czyli jak radzić sobie z rzeczywistością

  • 1. Domain Events Czyli jak radzić sobie z rzeczywistością! Mateusz Stasch | 2016.04.11
  • 3. ?
  • 4.
  • 9. Domain event is something that happened that domain experts care about. Anonymous
  • 11. NOW
  • 13. C D E H1 H2
  • 14. C D E H1 H2 Ext. System
  • 15. C D E H1 H2 Ext. System Sync Async
  • 16.
  • 17. public void RegisterCardPayment(EntityId id, CardPayment paymentDetails) { // Validation... var caseToBePaid = _caseDao.GetById(id); // It was not so simple... ;) caseToBePaid.Payments.Add(paymentDetails); caseToBePaid.RefreshOutstandingBalance(); _mmeGateway.RegisterPayment(/*...*/); if (paymentDetails.CardType == CardType.Credit) { // Message generation... _mailGateway.Send(/*...*/); } /* Send to PDA... */ }
  • 18. Business Logic PDA MME Mail
  • 19. Business Logic PDA MME Mail Test Scope
  • 20. Business Logic PDA MME Mail CBL * CPDA CMME CMail* * Test Scope
  • 21. public void RegisterCardPayment(EntityId id, CardPayment paymentDetails) { // Validation... var caseToBePaid = _caseDao.GetById(id); // It was not so simple... ;) caseToBePaid.Payments.Add(paymentDetails); caseToBePaid.RefreshOutstandingBalance(); _mmeGateway.RegisterPayment(/*...*/); if (paymentDetails.CardType == CardType.Credit) { // Message generation... _mailGateway.Send(/*...*/); } /* Send to PDA... */ }
  • 22. public void RegisterCardPayment(EntityId id, CardPayment paymentDetails) { // Validation... var caseToBePaid = _caseDao.GetById(id); // It was not so simple... ;) caseToBePaid.Payments.Add(paymentDetails); caseToBePaid.RefreshOutstandingBalance(); _eventBus.Raise(new CardPaymentRegisteredEvent { Id = id, Details = paymentDetails }); }
  • 23. public class CardPaymentRegisteredEvent : Event { public CardPayment Details { get; set; } }
  • 24. Business Logic PDA MME Mail
  • 25. public class MmePaymentsHandler : IEventHandler<CardPaymentRegisteredEvent> { private MMEGateway _mmeGateway; /* ctor(MMEGateway Gateway)... */ public void Handle(CardPaymentRegisteredEvent @event) { if (@event.Details.CardType == CardType.Credit) { _mmeGateway.Send(/*...*/); } } }
  • 26. public class MmePaymentsHandler : IEventHandler<CardPaymentRegisteredEvent> { private MMEGateway _mmeGateway; /* ctor(MMEGateway Gateway)... */ public void Handle(CardPaymentRegisteredEvent @event) { if (@event.Details.CardType == CardType.Credit) { _mmeGateway.Send(/*...*/); } } }
  • 30. public class MmePaymentsHandler : IEventHandler<CardPaymentRegisteredEvent> { private MMEGateway _mmeGateway; /* ctor(MMEGateway Gateway)... */ public void Handle(CardPaymentRegisteredEvent @event) { if (@event.Details.CardType == CardType.Credit) { _mmeGateway.Send(/*...*/); } } }
  • 32. Nie wiem ilu Was jest, kiedy i w jakiej kolejności wykonacie pracę oraz jaki będzie jej wynik
  • 36. PaymentRejectedEvent Zrób coś, bo Payment został odrzucony! #1
  • 38. Fakt, a nie życzenie! #1
  • 39. _eventBus.Raise(new CardPaymentRegisteredEvent { Id = id, Details = paymentDetails, Case = caseToBePaid }); #2
  • 40. _eventBus.Raise(new CardPaymentRegisteredEvent { Id = id, Details = paymentDetails, Case = caseToBePaid }); #2
  • 41. Zdarzenie powinno być małe* i serializowalne #2
  • 43. public void RegisterCardPayment(EntityId id, CardPayment paymentDetails) { var caseToBePaid = _caseDao.GetById(id); caseToBePaid.Payments.Add(paymentDetails); caseToBePaid.RefreshOutstandingBalance(); if (caseToBePaid.OutstandingBalance.IsZero) { caseToBePaid.MarkAsPaid(); } /* MME */ /* Mail */ /* Send to PDA... */ }
  • 44. public void RegisterCardPayment(EntityId id, CardPayment paymentDetails) { var caseToBePaid = _caseDao.GetById(id); caseToBePaid.Payments.Add(paymentDetails); caseToBePaid.RefreshOutstandingBalance(); if (caseToBePaid.OutstandingBalance.IsZero) { caseToBePaid.MarkAsPaid(); } /* MME */ /* Mail */ /* Send to PDA... */ }
  • 45. Nie wiem ilu Was jest, kiedy i w jakiej kolejności wykonacie pracę oraz jaki będzie jej wynik #3
  • 47. public void RegisterCardPayment(EntityId id, CardPayment paymentDetails) { var caseToBePaid = _caseDao.GetById(id); // It was not so simple... ;) caseToBePaid.Payments.Add(paymentDetails); caseToBePaid.RefreshOutstandingBalance(); if (caseToBePaid.OutstandingBalance.IsZero) { _eventBus.Raise(new CasePaidEvent { Id = id }); } _eventBus.Raise(new CardPaymentRegisteredEvent { Id = id, Details = paymentDetails }); } public void RegisterCashPayment(EntityId id /*...*/)
  • 48. public void RegisterCardPayment(EntityId id, CardPayment paymentDetails) { var caseToBePaid = _caseDao.GetById(id); // It was not so simple... ;) caseToBePaid.Payments.Add(paymentDetails); caseToBePaid.RefreshOutstandingBalance(); if (caseToBePaid.OutstandingBalance.IsZero) { _eventBus.Raise(new CasePaidEvent { Id = id }); } _eventBus.Raise(new CardPaymentRegisteredEvent { Id = id, Details = paymentDetails }); } public void RegisterCashPayment(EntityId id /*...*/)
  • 49. public void RegisterCardPayment(EntityId id, CardPayment paymentDetails) { var caseToBePaid = _caseDao.GetById(id); // It was not so simple... ;) caseToBePaid.Payments.Add(paymentDetails); caseToBePaid.RefreshOutstandingBalance(); if (caseToBePaid.OutstandingBalance.IsZero) { _eventBus.Raise(new CasePaidEvent { Id = id }); } _eventBus.Raise(new CardPaymentRegisteredEvent { Id = id, Details = paymentDetails }); } public void RegisterCashPayment(EntityId id /*...*/)
  • 50. public void RegisterCardPayment(EntityId id, CardPayment paymentDetails) { var caseToBePaid = _caseDao.GetById(id); // It was not so simple... ;) caseToBePaid.Payments.Add(paymentDetails); caseToBePaid.RefreshOutstandingBalance(); if (caseToBePaid.OutstandingBalance.IsZero) { _eventBus.Raise(new CasePaidEvent { Id = id }); } _eventBus.Raise(new CardPaymentRegisteredEvent { Id = id, Details = paymentDetails }); } public void RegisterCashPayment(EntityId id /*...*/) Utrata kontroli
  • 51.
  • 52. public void RegisterCardPayment(EntityId id, CardPayment paymentDetails) { var caseToBePaid = _caseDao.GetById(id); // It was not so simple... ;) caseToBePaid.Payments.Add(paymentDetails); caseToBePaid.RefreshOutstandingBalance(); _eventBus.Raise(new CardPaymentRegisteredEvent { Id = id, Details = paymentDetails }); } public void RegisterCashPayment(EntityId id /*...*/)
  • 53. Jedno zdarzenie ma jedno źródło! #4
  • 54. public void AddGood(EntityId id, Good good) { var @case = _caseDao.GetById(id); @case.AddGood(good); _mmeGateway.Send(/*...*/ @case.Balance); /* Other stuff */ } #5
  • 55. public void AddGood(EntityId id, Good good) { var @case = _caseDao.GetById(id); @case.AddGood(good); _mmeGateway.Send(/*...*/ @case.Balance); /* Other stuff */ } #5
  • 56. #5public class GoodAddedEvent : IEvent { public EntityId Id { get; set; } public DateTimeOffset RaisedAt { get; set; } public Good Good { get; set; } public Money Balance { get; set; } }
  • 57. #5public class GoodAddedEvent : IEvent { public EntityId Id { get; set; } public DateTimeOffset RaisedAt { get; set; } public Good Good { get; set; } public Money Balance { get; set; } }
  • 58. public void AddGood(EntityId id, Good good) { var @case = _caseDao.GetById(id); @case.AddGood(good); /* Raise Event */ _mailGateway.Send(/*...*/ @case.OutstandingBalance); /* Other stuff */ } #5
  • 59. #5 Nie modeluj zdarzenia dla konkretnego handlera
  • 60. ReCap • Fakt, a nie życzenie! • Obiekt zdarzenia powinien być mały • Nie polegaj na skutkach ubocznych swojej implementacji • Jedno zdarzenie ma jedno źródło • Nie modeluj zdarzenia dla jednego handlera • Nie używajcie EF-a.
  • 62.
  • 63. Refactoring  Powiadomienia(Maile, SMSy)  Integracje z zew. systemami o ile nie są krytyczne*  Eager Data Derivation  Generowanie dokumentów/raportów  Unieważnianie :D Cache
  • 65. public interface IEvent { int Id { get; set; } Type EntityType { get; set; } } public interface IEventHandler<TEvent> where TEvent : IEvent { void Handle(TEvent @event); }
  • 68. private void ApplyEvents() { var processed = new List<IEvent>(); for (;;) { var events = ChangeTracker.Entries<IEventSource>() .SelectMany(x => x.Entity.Events) .Except(processed) .ToList(); if (!events.Any()) break; foreach (var @event in events) { _eventDispatcher.Apply(@event); processed.Add(@event); } } } public override int SaveChanges() { ApplyEvents(); base.SaveChanges(); }
  • 69. private void ApplyEvents() { var processed = new List<IEvent>(); for (;;) { var events = ChangeTracker.Entries<IEventSource>() .SelectMany(x => x.Entity.Events) .Except(processed) .ToList(); if (!events.Any()) break; foreach (var @event in events) { _eventDispatcher.Apply(@event); processed.Add(@event); } } } public override int SaveChanges() { ApplyEvents(); base.SaveChanges(); }
  • 70. private void ApplyEvents() { var processed = new List<IEvent>(); for (;;) { var events = ChangeTracker.Entries<IEventSource>() .SelectMany(x => x.Entity.Events) .Except(processed) .ToList(); if (!events.Any()) break; foreach (var @event in events) { _eventDispatcher.Apply(@event); processed.Add(@event); } } } public override int SaveChanges() { ApplyEvents(); base.SaveChanges(); }
  • 71. private void ApplyEvents() { var processed = new List<IEvent>(); for (;;) { var events = ChangeTracker.Entries<IEventSource>() .SelectMany(x => x.Entity.Events) .Except(processed) .ToList(); if (!events.Any()) break; foreach (var @event in events) { _eventDispatcher.Apply(@event); processed.Add(@event); } } } public override int SaveChanges() { ApplyEvents(); base.SaveChanges(); }
  • 72. private void ApplyEvents() { var processed = new List<IEvent>(); for (;;) { var events = ChangeTracker.Entries<IEventSource>() .SelectMany(x => x.Entity.Events) .Except(processed) .ToList(); if (!events.Any()) break; foreach (var @event in events) { _eventDispatcher.Apply(@event); processed.Add(@event); } } } public override int SaveChanges() { ApplyEvents(); base.SaveChanges(); }
  • 73. public class EventDispatcher : IEventDispatcher { /*...*/ public void Apply(IEvent @event) { // ... Call generic ApplyTyped } protected void ApplyTyped<TEvent>(TEvent @event) where TEvent : IEvent { var handlers = _scope.Resolve<IEnumerable<IEventHandler<TEvent>>>(); foreach (var eventHandler in handlers) { eventHandler.Handle(@event); } } }
  • 74. public class EventDispatcher : IEventDispatcher { /*...*/ public void Apply(IEvent @event) { // ... Call generic ApplyTyped } protected void ApplyTyped<TEvent>(TEvent @event) where TEvent : IEvent { var handlers = _scope.Resolve<IEnumerable<IEventHandler<TEvent>>>(); foreach (var eventHandler in handlers) { eventHandler.Handle(@event); } } }
  • 75. public void Apply(IEvent @event) { try { applyTypedMethod.MakeGenericMethod(@event.GetType()) .Invoke(this, new object[] { @event }); } catch (TargetInvocationException ex) { ex.InnerException.PreserveStackTrace(); throw ex.InnerException; } }
  • 76. public class AgreementSubmitted : IEvent { public DateTime EffectiveDate { get; set; } public string Note { get; set; } public int Id { get; set; } public Type EntityType { get; set; } public AgreementSubmitted(int id, DateTime effectiveDate, string note) { Id = id; EffectiveDate = effectiveDate; Note = note; } }
  • 77. public void Handle(AgreementSubmitted @event) { SendEmail(ApprovalRequestEmailCode, @event.Id, pa => pa.Administrators); }
  • 78. Event Log jako Log Historia pewnego włamania...
  • 79. public class EventPersister<TEvent> : IEventHandler<TEvent> where TEvent : IEvent { private readonly IEventStore _eventStore; public void Handle(TEvent @event) { _eventStore.Save(new EventEnvelope<TEvent>(@event)); } }
  • 80. SELECT * FROM EventLog WHERE EntityType = 'NS.Case' AND Id = 302049 ORDER BY RaisedAt Id EntityType RaisedAt RaisedBy EventType Content 302049 Domain.Case 2016-01-01 20:54:43.104 56 Events.Case.Created {…} 302049 Domain.Case 2016-01-01 20:55:43.105 56 Events.Case.CardPaymentRegistered {…} 302049 Domain.Case 2016-03-01 15:01:13.554 76 Events.Case.GoodsCollected {…} 302049 Domain.Case 2016-03-01 15:01:13.555 1 Events.Case.Paid {} 302050 Domain.Case 2016-03-01 15:01:13.556 1 Events.Case.Closed {}
  • 81. SELECT * FROM EventLog WHERE EntityType = 'NS.Case' AND Id = 302049 ORDER BY RaisedAt Id EntityType RaisedAt RaisedBy EventType Content 302049 Domain.Case 2016-01-01 20:54:43.104 56 Events.Case.Created {…} 302049 Domain.Case 2016-01-01 20:55:43.105 56 Events.Case.CardPaymentRegistered {…} 302049 Domain.Case 2016-03-01 15:01:13.554 76 Events.Case.GoodsCollected {…} 302049 Domain.Case 2016-03-01 15:01:13.555 1 Events.Case.Paid {} 302050 Domain.Case 2016-03-01 15:01:13.556 1 Events.Case.Closed {}
  • 85. Dzięki! Domain Events Czyli jak radzić sobie z rzeczywistością! Mateusz Stasch | 2016.04.11