History is first-class
Past business actions remain explicit instead of being flattened into a single latest row.
Event Sourcing replaces current-state storage as the primary source of truth with an append-only stream of domain events. That can be powerful when business history matters deeply, when reconstruction is valuable, or when projections must be rebuilt in different forms. It is also one of the most over-applied distributed patterns, so judgment matters.
In ordering, knowing that an order was placed, payment authorized, stock reserved, shipment created, and refund issued is often more valuable than just seeing the latest status. Event Sourcing keeps that history explicit and reconstructable, which can be useful for audits, debugging, and multiple read models.
With Event Sourcing, the system appends events such as OrderPlaced, PaymentAuthorized, and ShipmentCreated. Current state is rebuilt by replaying those events into an aggregate or projection. This can improve auditability and temporal reasoning, but it also introduces versioning, replay, and event evolution challenges.
Use Event Sourcing when the business meaning of historical change is central, not because events seem architecturally elegant. Many systems benefit more from ordinary persistence plus domain events than from full event sourcing.
Past business actions remain explicit instead of being flattened into a single latest row.
Current state comes from replaying events or maintaining projections.
Events live long, so schema evolution and compatibility become major concerns.
Payments, compliance-sensitive workflows, and business timelines often benefit from a durable event history.
When teams need to answer how and why the state changed over time, event streams are more honest than overwritten rows.
If the history is rarely useful and replay cost adds confusion, current-state persistence is usually better.
Event sourcing magnifies naming, versioning, and compatibility mistakes.
package org.javaomnibus.orders.eventsourcing;
public final class OrderAggregate {
private OrderStatus status;
public void apply(OrderPlaced event) {
this.status = OrderStatus.PENDING_PAYMENT;
}
public void apply(PaymentAuthorized event) {
this.status = OrderStatus.PAID;
}
public void apply(ShipmentCreated event) {
this.status = OrderStatus.FULFILLING;
}
}