Skip to main content

46. Defer Event Sourcing and CQRS

Status: Accepted Date: 2025-07-06

Context

For complex, high-throughput systems like a trading platform, architectural patterns like Event Sourcing (ES) and Command Query Responsibility Segregation (CQRS) are often considered. Event Sourcing provides a perfect audit log by storing every state change as an immutable event. CQRS can improve performance and scalability by creating separate, optimized models for read and write operations. However, these patterns introduce significant complexity in terms of implementation, developer learning curve, and managing eventual consistency. We need to decide if the benefits of ES/CQRS outweigh these costs for the Mercury system at its current stage.

Decision

We will not implement Event Sourcing or CQRS for the initial architecture of the Mercury system. Instead, we will adopt a more traditional, state-oriented persistence model using a relational database (PostgreSQL) and a standard service layer architecture.

The current state of entities (e.g., Accounts, Positions, Tournaments) will be stored directly in database tables. Business logic will be handled in service classes that perform standard CRUD (Create, Read, Update, Delete) operations.

This decision will be revisited in the future if a specific bounded context or service demonstrates performance or auditing requirements that cannot be met by this simpler architecture.

Consequences

Positive:

  • Reduced Complexity: The chosen architecture is well-understood by most developers, significantly reducing the learning curve and implementation complexity.
  • Faster Development: Development velocity will be higher as we are using a familiar, simpler pattern with mature tooling (e.g., MikroORM).
  • Strong Consistency: A traditional relational database approach provides strong consistency by default, which is easier to reason about than the eventual consistency often found in CQRS systems.
  • Simpler Tooling: We avoid the need for specialized event stores (like Kafka or a dedicated event store database) and complex projection logic.

Negative:

  • No Built-in Audit Log: We lose the inherent, perfect audit log that Event Sourcing provides. Any auditing capabilities must be implemented explicitly.
  • Potential for Performance Bottlenecks: In a traditional model, the same database tables are used for both reads and writes, which can sometimes lead to contention and performance bottlenecks under very high load.

Mitigation:

  • Explicit Auditing: For entities that require a detailed history (e.g., orders, transactions), we will create explicit audit log tables or use database triggers to record all state changes. This provides "good enough" auditing without the full complexity of ES.
  • Read Replicas: If read performance becomes an issue, we can introduce database read replicas to scale out the read operations, which is a simpler form of read/write segregation than full CQRS.
  • Focused Optimization: If a specific part of the system becomes a bottleneck, we can apply targeted optimizations to that area, or even reconsider ES/CQRS for just that single, well-understood component, rather than applying it to the entire system prematurely.