Blog Hoch
Mar 2026·2 tup leghDe'wI' chenmoHta'

Event Sourcing vs Traditional CRUD

#architecture#backend#databases

traditional CRUD table row current state nob, chay' ghoS pagh. event sourcing choH: change Hoch (qaS) store, current state compute (store pagh). inversion real problems solve 'ej chu' Qagh chenmoH - cha' yaj qaSpa'.

CRUD: state in place, history nuqDaq pagh

normal orders table update row overwrite:

UPDATE orders SET status = 'shipped', shipped_at = now() WHERE id = 4821;

run qaSDI' previous status gone (audit log table, application-level logging, trigger separately capture pagh vaj). customer "order shipped legh 'ach shipping notification pagh" jey 'ej answer: bug jaj wej qaSpa' shipped brief flip back - CRUD table information ghajbe'.

event sourcing: log source of truth

current state store pagh - append-only events sequence store, current state replay derive:

// events, in order, for order 4821
[
  { type: 'OrderPlaced', orderId: 4821, items: [...], at: '2026-03-20T10:00:00Z' },
  { type: 'PaymentReceived', orderId: 4821, amount: 4999, at: '2026-03-20T10:01:12Z' },
  { type: 'OrderShipped', orderId: 4821, carrier: 'ups', at: '2026-03-22T14:30:00Z' },
]

current state list fold:

function projectOrder(events) {
  return events.reduce((state, event) => {
    switch (event.type) {
      case 'OrderPlaced':
        return { ...state, id: event.orderId, items: event.items, status: 'placed' };
      case 'PaymentReceived':
        return { ...state, status: 'paid', paidAmount: event.amount };
      case 'OrderShipped':
        return { ...state, status: 'shipped', carrier: event.carrier };
      default:
        return state;
    }
  }, {});
}

const currentOrder = projectOrder(eventsForOrder(4821));

pagh delete pagh overwrite. full history (order pass Hoch state, exactly qaSDI') model Daq inherent (separate system maintain pagh).

actually gain

  • real audit trail, free. "nuq qaS, order" primary data (derived log pagh).
  • Time travel. past point Hoch state project (timestamp Dung events replay) - debugging ("bug report qaSpa' nuq") 'ej compliance Daq useful.
  • new read models, write logic touch pagh. new view data (revenue per day, orders per carrier) dashboard vaD? existing event stream over new projection function ghItlh. events choH pagh.
  • write read paths decouple. events write model; projections read models (asynchronously law'). CQRS (Command Query Responsibility Segregation) Daq jaH: writes reads independently scale evolve.

actually cost

  • query Hoch projection poQ. "order 4821 current status" row lookup pagh - events replay (snapshot cache + last snapshot qaSDI' events replay).
// snapshot every 50 events instead of replaying from the start each time
function projectWithSnapshot(orderId, snapshot, eventsSinceSnapshot) {
  return eventsSinceSnapshot.reduce(applyEvent, snapshot ?? initialState());
}
  • schema evolution harder. old event meaning choH laHbe' - code today three years qaSpa' OrderPlaced event correctly interpret poQ. new event type chel Dun; existing structure choH version (OrderPlacedV2) 'ej old handler indefinitely keep.
  • deletion awkward (purpose). "customer data delete" (GDPR real requirement) vs "events immutable never deleted". real systems crypto-shredding (personal fields per-customer key encrypt, key delete) - events log vo' remove pagh.
  • debugging sequences think (snapshots pagh). "row nuq Qagh" "40 events sequence 'ej projection logic nuq Qagh" - different debugging mindset (team poH poQ).

worth

event sourcing history real business value ghaj vaj earn: financial ledgers, order lifecycles, audit compliance requirements, "nuq choH 'ej qatlh" first-class question. users table display_name avatar_url track: poQbe' - profile picture audit trail vay' jey pagh.

middle ground: outbox / audit tables full event sourcing pagh

all-or-nothing choose poQ pagh. common practical pattern: normal CRUD table current state, order_events append-only table write Hoch rap same transaction Daq populate:

BEGIN;
UPDATE orders SET status = 'shipped' WHERE id = 4821;
INSERT INTO order_events (order_id, type, payload, at)
  VALUES (4821, 'OrderShipped', '{"carrier":"ups"}', now());
COMMIT;

audit trail 'ej debugging time-travel benefits tlhap (read Hoch replay pagh) - current state direct row lookup. "read models new projections" flexibility lose 'ach applications law' fair trade (build reason simpler).

yaj

CRUD where store; event sourcing how got there store, where derive. audit trail, time travel, flexible read models real valuable - harder schema evolution, awkward deletion, different debugging model rap. history system point vaj full event sourcing; pagh vaj audit table normal CRUD rap benefit most, complexity fraction.

chu'JWT Authentication Qu' lIjqanStructured Logging: printf debugging scale Qu'be'