Use an event-driven architecture

· 4 min read · 651 words
#architecture #best-practices

Architecture matters more than ever!

Forensic debugging has always been a painful process; but AI makes it far easier. Using an event-driven architecture removes the guesswork and gives the AI agents a precise path to diagnose issues.


Agents need evidence, not snapshots

In a traditional CRUD system, the database only knows what things look like now. When a bug corrupts some data, the history is gone, and the agent is left guessing how it happened.

An event-driven system keeps every change as an immutable event. State is just the result of replaying them. That gives an agent something it’s genuinely good at: reading a structured timeline and reasoning about it.

Anatomy of a debuggable event

Name {Entity}{PastTenseVerb}

For example OrderCancelled. Specific names let an agent follow the story without reading your code first.

Payload {The data that changed}

Metadata {Timestamp} {Correlation ID} {Causation ID}

This is what lets an agent trace a chain of events back to the request that started it.

Some examples

Never give an agent this

orders.status = 'cancelled'   -- but why?

Give it this

10:14:02  PaymentDeclined   order=4821  corr=req-9f3a
10:14:02  OrderCancelled    order=4821  cause=PaymentDeclined
10:14:05  PaymentSucceeded  order=4821  corr=req-9f3a  (retry)

Note how the bug is almost visible on its own: the order was cancelled on the first decline, before the retry succeeded. An agent can spot that in seconds and point you to the handler responsible.

Traditional vs event-driven: a real investigation

Our iPad app needs to work offline, so it keeps its own copy of the data and syncs with the server when it can. Recently a customer complained that some of their changes weren’t showing up, and it turned out the server’s copies of some JSON files were out of sync with what was on the device.

The traditional way

With no history, the agent had to piece the timeline together by comparing upload timestamps against the records in the database:

uploads/  job_4821.json       modified 2026-11-03 09:12:44
db        jobs.id=4821        updated_at 2026-11-03 09:40:02
device    job_4821.json       modified 2026-11-03 09:35:18

From here, it’s all inference. Was the 09:12 upload stale by the time it arrived? Did the 09:35 edit on the device ever reach the server? What changed the database at 09:40? And because the iPad was offline, its clock and the server’s clock don’t necessarily agree. The agent can offer theories, but it can’t prove any of them, and neither can you.

The event-driven way

The same investigation, with the device recording its changes as events and syncing them to the server:

device seq=41  09:12:40  JobUpdated  job=4821  field=notes
device seq=42  09:35:18  JobUpdated  job=4821  field=status
server         09:40:02  SyncReceived  device=ipad-07  seq=41  (seq=42 missing)

There’s no guessing. The device made two changes, but only the first one reached the server. The agent can see the gap in the sequence numbers immediately and go straight to the sync code to find out why event 42 was dropped.

The difference is that timestamps tell you when things changed, while events tell you what changed and in what order. That matters even more in an offline-first app, where clocks can’t be trusted but sequence numbers can. An agent working from timestamps is doing archaeology; an agent working from events is reading the minutes.

Replay is the killer feature

Because state is derived from events, an agent can:

  • Rebuild the system as it was just before the bug
  • Form a hypothesis and test it against the real event stream
  • Replay the same events against a fix to prove it works

That’s a full forensic loop with no guesswork. Martin Fowler covers the underlying pattern in Event Sourcing.


Event-driven architecture isn’t a silver bullet, and it adds real complexity. But if you’re going to hand debugging to an agent, giving it a complete record of what happened beats asking it to reverse-engineer a crime scene.