DDD
Message types:
- Command: an expression of intent to trigger an action in the domain.
- Routing: routed to a single handler (via consistent hashing).
- Outcome: provides confirmation/result (sync or async).
- Event: a notification (if subscribed) that something relevant has happened inside the domain.
- Routing: distributed to all logical handlers (ordering required).
- Outcome: no results from handling.
- Query: a request for information or state.
- Routing: route with load balancing.
- Outcome: always provides result.
Location Transparency:
- A component should neither be aware of nor make any assumptions about the location of other components it interacts with.
Message Bus
- Moves messages from one component to another.
- Enables location transparency.
Events
- Events should represent business/domain events, not necessarily database events; so their names should match the language that our customers speak.
- Use domain semantics instead of CRUD semantics for naming events (e.g. Employees are not Created/Updated/Deleted, they are Hired/Promoted/Terminated/Retired).
- Have a granular (instead of broad) "Updated" event model so that transport as few fields as possible and so that event handlers handle only those event relevant to them.
Event Store
- An event store stores the published events.
Kafka
- Great for Event Streaming not for Event Sourcing.
Event Streaming
- Service A published an event, Service B consumes the event.
Event Sourcing
- Service A published an event, Service B picks all older events and consumes the latest event to process it.
- The state of an application is not stored within a single record/event, instead it is stored in an array of events.
Event Store
- Single source of truth.
- Events are appended only (not deletions or modifications).
- Event sequence is validated to maintain the order.
- Full sequential read (for all aggregates, e.g. to construct projections).
- Able to read a particular aggregate's events.
Invariant
- An invariant is a constraint enforced by a validation.
Bounded Context
- A bounded context groups together a model that may have 1 or many objects.
Aggregate
- An event sourced aggregate is not a view of the aggregate or its underlying entities. It’s a transactional boundary.
- Before any processing of commands, the aggregate must be brought up to date by running all past historical events (or maybe commands).
- The purpose of the aggregate is to:
- help validate incoming commands (enforcing the invariants within a bounded context)
- produce any resulting events
- A command-side aggregate only needs to maintain enough state (i.e. fields) necessary to validate commands and to allow for the creation of the resulting events.
- May have very few fields from the “view” or underlying entity, and may have additional details not found in the “view”, but required for validation.
Entity
- An entity is an object that differs by ID.
Use input validation -> Command runnable validation (by Aggregate) -> Event generation.