We implemented event sourcing for a basic CRUD app because "it's the right way." Spent 6 months on infrastructure instead of features.

The app requirements:

  • User management CRUD
  • 500 daily users
  • No audit requirements
  • No time-travel needed
  • Standard business logic

What we built:

  • Event store on Kafka + PostgreSQL — itself a questionable call: Kafka as an event store gives you no per-aggregate reads and awkward retention semantics, which cost us extra workarounds
  • Event replay system
  • Projections (read models)
  • Snapshotting
  • Versioned events
  • Saga orchestration

Time spent:

  • Infrastructure: 4 months
  • Event schema design: 1 month
  • Debugging eventual consistency: 1 month
  • Actual business features: 2 weeks

The consistency-debugging month, in one example: a user changed their email, the confirmation screen still showed the old address because the read model lagged, they retried — and we spent two days tracing duplicate EmailChanged events through a projection rebuild. For a form that updates one row.

What we needed:

class User:
    def update(self, data):
        self.name = data.name
        self.email = data.email
        db.save(self)

When event sourcing makes sense:

  • Regulatory audit trail requirements
  • Financial transactions
  • Time-travel debugging
  • Complex domain with many state transitions

Lesson: Event sourcing is powerful. It's also expensive. Match complexity to requirements — the same instinct that leads small teams into microservices they don't need.


← Back to Lessons Learned