Entities,

Aggregates,

and Events

What is Entity?

What is Aggregate?

Entities

vs

Aggregates

Entity

  1. Has ID
  2. Not accessible from outside of Aggregate it belongs to
  3. i.e. individual Transactions for Bank Account

Aggregate

  1. Has aggregate root
  2. Hides underlying Entities from direct modification
  3. i.e. Bank Account and it's Transactions

Applying Event

on Aggregate

BankAccount::Created.call
BankAccount::Approved.call
BankAccount::Blocked.call
BankAccount::Destroyed.call

BankAccount::TransactionsImported.call
BankAccount::WithdrawalSuccessful.call

"Updated" trap

a.k.a. update everything!

def WWW
  # [...]
  BankAccount::Updated.call bank_account_id: id
end

def XXX
  # [...]
  BankAccount::Updated.call bank_account_id: id
end

def YYY
  # [...]
  BankAccount::Updated.call bank_account_id: id
end

def ZZZ
  # [...]
  BankAccount::Updated.call bank_account_id: id
end
def create_bank_account
  # [...]
  BankAccount::Updated.call bank_account_id: id
end

def approve_bank_account
  # [...]
  BankAccount::Updated.call bank_account_id: id
end

def import_transactions
  # [...]
  BankAccount::Updated.call bank_account_id: id
end

def destroy_bank_account
  # [...]
  BankAccount::Updated.call bank_account_id: id
end
def create_bank_account
  # [...]
  BankAccount::Created.call bank_account_id: id, organization_id: id, [...]
end

def approve_bank_account
  # [...]
  BankAccount::Approved.call bank_account_id: id
end

def import_transactions
  # [...]
  BankAccount::TransactionsReplaced.call bank_account_id: id,
                                         transactions: [...]
end

def destroy_bank_account
  # [...]
  BankAccount::Destroyed.call bank_account_id: id
end

Rule of

Reversible EventĀ 

class BankAccount
  class Created
    def self.call(bank_account_id: id, organization_id: id, [...])
      # [...]
    end
  end

  class Approved
    def self.call(bank_account_id: id)
      # [...]
    end
  end

  class TransactionsReplaced
    def self.call(bank_account_id: id, transactions: [...])
      # [...]
    end
  end

  class Destroyed
    def self.call(bank_account_id: id)
      # [...]
    end
  end
end

Enriching Events

a.k.a. "but someone need this in payload"

BankAccount::Approved.call bank_account_id: id, transactions: [...]
BankAccount::Approved.call bank_account_id: id

class BankAccount::ApprovedHandler

  def call(bank_account_id:)
    transactions = TransactionsQuery.for_bank_account bank_account_id

    Enriched::BankAccount::Approved.call bank_account_id: bank_account_id,
                                         transactions: transactions
  end

end

"Succeeded"

Entities, Aggregates, and Events

By Bernard Potocki

Entities, Aggregates, and Events

  • 988