Implementing Event-Driven Architecture

1. Understanding Event Sourcing Pattern

PropertyDetail
State derivationState = fold(events)
Append-onlyEvents immutable
Audit logBuilt-in history
Time travelReplay to any point
ExamplesEventStoreDB, Axon, Marten

2. Implementing Event Store Design

ElementDetail
StreamPer-aggregate event sequence
Event idUUID, deduplication anchor
Sequence numberPer-stream monotonic
Global positionTotal order across streams
Optimistic concurrencyAppend with expected version

3. Implementing Event Replay and Projection

Example: Account projection

public class AccountProjection {
    private long balance = 0;

    public void apply(DepositedEvent e) { balance += e.amount; }
    public void apply(WithdrawnEvent e) { balance -= e.amount; }

    public static AccountProjection rebuild(List<Event> events) {
        AccountProjection p = new AccountProjection();
        for (Event e : events) p.dispatch(e);
        return p;
    }
}
OptimizationDetail
SnapshotsFold every N events; replay tail only
Materialized viewsPersist projections for queries
Catch-up subscriptionsSubscribe from last position

4. Understanding CQRS Pattern

SideModel
CommandValidates, mutates, emits events
QueryRead-optimized projections
SyncEvents propagate from write → read
ProsIndependent scaling and schema
ConsEventual consistency between sides

5. Implementing Event Bus

ImplementationDetail
In-processSpring ApplicationEventPublisher, MediatR
DistributedKafka, RabbitMQ, NATS, EventBridge
Schema registryConfluent, Apicurio for evolution
CloudEvents specStandardized envelope

6. Implementing Event Schema Evolution

StrategyDetail
Additive onlyNew optional fields safe
Versioned event typesOrderCreatedV2
UpcasterTransforms old events on read
Compatibility modeSchema registry enforces BACKWARD

7. Handling Event Ordering and Causality

GuaranteeMechanism
Per-aggregate orderPartition by aggregate id
Causal across aggregatesVector clock / causal id
Total orderSingle partition (limited throughput)
Out-of-order toleranceWatermarks, late event handling

8. Implementing Event Deduplication

MethodDetail
Event id setTrack processed ids in DB / Redis
Idempotent handlersApply naturally idempotent
Producer dedup idKafka enable.idempotence=true
Window-based dedupFixed time window (Flink)

9. Understanding Domain Events vs Integration Events

Domain Events

  • Internal to bounded context
  • Rich domain language
  • Synchronous in-process
  • Coupled to internal model

Integration Events

  • Cross bounded context / service
  • Stable contract; versioned
  • Asynchronous over broker
  • Decoupled from internals

10. Implementing Outbox Pattern

Transactional Outbox

  1. In single DB transaction: write entity + insert into outbox table
  2. Background relay polls outbox or reads CDC log (Debezium)
  3. Publish to broker (Kafka, RabbitMQ)
  4. Mark outbox row as published / delete
  5. Consumers dedup using event id
Note: Outbox guarantees no event lost when DB commits, eliminating dual-write inconsistency.