Będę mówił o tym jak radzić sobie z zastanym stanem świata. Dlaczego z zastanym? Bo skoro już reagujemy na zdarzenie, to coś się stało i się nie odstanie. Koniec kropka. W trakcie wykładu postaram się wprowadzić koncepcję zdarzeń domenowych, opowiedzieć gdzie plasują się one na płaszczyźnie szeroko pojętego i przeładowanego w IT słowa event. Opowiem jak implementować zdarzenia, co jest zdarzeniem, a co nie jest oraz jakie benefity i koszty wnoszą do naszego kodu. Pokażę także, jak zdarzenia wykorzystać żeby ułatwić sobie pracę oraz podzielę się ze słuchaczami kilkoma regułami kciuka, które stosuję w trakcie pracy ze zdarzeniami.
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... */
}
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
});
}
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 /*...*/)
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
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.
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);
}
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;
}
}