Your First Events
We now need to design the aggregate events that will form as the basis of your domain. Some of events that occur in this system could be:
- Bank account has been opened.
- Money has been sent to a bank account.
- Bank fees for the sending of money have been deducted from bank account.
- Money has been received by a bank account.
Lets model these events accordingly.
The event that represents a bank account being opened
//Walkthrough.Domain/Model/Account/Events/AccountOpenedEvent.cspublic class AccountOpenedEvent : AggregateEvent<Account,AccountId>{public Money OpeningBalance { get; }public AccountOpenedEvent(Money openingBalance){OpeningBalance = openingBalance;}}
The event that represents a bank account having sent money
//Walkthrough.Domain/Model/Account/Events/MoneySentEvent.cspublic class MoneySentEvent : AggregateEvent<Account,AccountId>{public Transaction Transaction { get; }public MoneySentEvent(Transaction transaction){Transaction = transaction;}}
The event that represents a bank account deducting bank fees
//Walkthrough.Domain/Model/Account/Events/FeesDeductedEvent.cspublic class FeesDeductedEvent : AggregateEvent<Account,AccountId>{public Money Amount { get; }public FeesDeductedEvent(Money amount){Amount = amount;}}
The event that represents a bank account receiving money
//Walkthrough.Domain/Model/Account/Events/MoneyReceivedEvent.cspublic class MoneyReceivedEvent : AggregateEvent<Account,AccountId>{public Transaction Transaction { get; }public MoneyReceivedEvent(Transaction transaction){Transaction = transaction;}}
We need to add each aggregate event applier method to the aggregate state as an IApply<>
.
AccountState
becomes:
//Walkthrough.Domain/Model/Account/AccountState.cspublic class AccountState : AggregateState<Account, AccountId>,IApply<AccountOpenedEvent>,IApply<MoneySentEvent>,IApply<FeesDeductedEvent>,IApply<MoneyReceivedEvent>{public Money Balance { get; }public void Apply(AccountOpenedEvent aggregateEvent){Balance = aggregateEvent.OpeningBalance;}public void Apply(MoneySentEvent aggregateEvent){Balance -= aggregateEvent.Transaction.Amount;}public void Apply(FeesDeductedEvent aggregateEvent){Balance -= aggregateEvent.Amount;}public void Apply(MoneyReceivedEvent aggregateEvent){Balance += aggregateEvent.Transaction.Amount;}}
Notice how events are treated as facts. The only domain logic here is how to apply the event to the aggregate state. If you have
if-else
statements in your state model, reconsider your modelling of events and state.
Head over to the next section on specifications.