Hello! Welcome to the final module, System Design & Production Readiness.
In our last lesson, we designed the "seams" of our system by defining API contracts and choosing communication protocols like REST, gRPC, and GraphQL. We now know how our services can talk to each other. The next critical question in any system design interview is: "How does each service manage its own data?"
Today, you will learn to select and justify data management strategies (e.g., CQRS, event sourcing) for different services within the system. This is a topic that clearly separates junior from senior candidates. It's not just about knowing the patterns, but about articulating the complex trade-offs and knowing when the added complexity is justified. This is especially crucial in domains like fintech, where auditability and performance are paramount.
1. Beyond Simple CRUD
For many microservices, a traditional CRUD (Create, Read, Update, Delete) model is sufficient. You have a single data model (e.g., a JPA entity), a single database, and your service performs operations on it. This is the default and simplest approach.
However, this simplicity comes with limitations that become problematic in complex systems:
- Model Contention: The same data model has to serve both write operations (which need consistency and validation) and read operations (which may need complex joins and aggregations). It's often optimized for neither.
- Performance Bottlenecks: In a read-heavy system, write operations can lock tables and slow down reads, and vice-versa.
- Lack of History: The database typically only stores the current state of an entity. If you need to know what a user's account balance was yesterday, you're out of luck unless you've built a separate, cumbersome audit log.
To overcome these challenges, we use more advanced patterns. Let's start with a high-level overview.
What is Event Sourcing and CQRS? (EDA - part 3)
To begin, let's watch this excellent short video from 'A Dev' Story'. It provides a clear, visual introduction to the two key patterns we'll discuss today: Event Sourcing and CQRS.
Watch the entire video (it's about 8 minutes). Focus on: Event Sourcing: Understand the core idea of storing events in a log instead of state in a table. CQRS: Grasp the fundamental principle of separating the 'write' path from the 'read' path. The Connection: Notice how the two patterns are often used together.
Now that you have a conceptual foundation, let's dissect each pattern in more detail.
2. Event Sourcing (ES): Your Data as an Immutable Story
As the video explained, Event Sourcing (ES) shifts the paradigm from storing the current state to storing a chronological sequence of immutable state changes, called events.
Think of it like a bank ledger. The bank doesn't just store your current balance. It stores a list of all transactions (deposits, withdrawals). Your current balance is simply the result of replaying all those transactions.
CQRS and Event Sourcing in Java
The Baeldung article 'CQRS and Event Sourcing in Java' provides a great textual breakdown of these concepts. We'll use it to solidify our understanding.
Please read sections 2.1 ('Event Sourcing'), 5 ('Introducing Event Sourcing'), and 5.3 ('Benefits and Drawbacks of Event Sourcing'). Focus on the definition of an event, how state is reconstructed, and the pros and cons.
Key Takeaways on Event Sourcing:
- Source of Truth: The event log is the single source of truth. The current state is a projection derived from the log.
- Immutability: Events are facts about what happened. They are never deleted or updated. If a mistake is made, a new compensating event is appended to correct it.
When to Justify Event Sourcing:
- Strict Audit Requirements (The #1 Reason): When you must be able to prove exactly how an entity reached its current state and what its state was at any point in history. This is a legal requirement in finance (FinTech), healthcare, and insurance.
- Powerful Debugging and Analytics: You can replay events to diagnose bugs or build new analytical models on historical data without impacting the live system.
- High Write Throughput: Appending events to a log is typically much faster than updating rows in a transactional database, reducing lock contention.
The Major Challenge: Querying the current state can be slow if it requires replaying thousands of events. This is mitigated using snapshots, where the system periodically calculates and saves the current state. To get the latest state, you load the most recent snapshot and only replay the events that have occurred since.
3. CQRS: The Two-Lane Highway for Your Data
CQRS (Command Query Responsibility Segregation) is a simpler pattern that addresses a different problem: the conflict between read and write workloads. The core idea is to create two distinct models:
- The Command Model (Write Side): Handles all state changes. It processes Commands (intents to change state, like
CreateUserCommand), enforces business rules, and updates the data store. Its focus is on consistency and validation. - The Query Model (Read Side): Handles all data retrieval. It exposes optimized, often denormalized read models (or "projections") tailored for specific UI screens or reports. Its focus is on speed and efficiency.
CQRS and Event Sourcing in Java
Let's return to the Baeldung article to explore CQRS.
Now, read sections 2.2 ('CQRS'), 4 ('Introducing CQRS'), and 4.4 ('Benefits and Drawbacks of CQRS'). Pay close attention to the separation of models, the concept of a 'Projector', and the problem of consistency.
When to Justify CQRS:
- Unbalanced Read/Write Loads: In a system like a social media feed or an e-commerce catalog, you might have thousands of reads for every one write. CQRS allows you to scale the read infrastructure (e.g., by adding more read replicas) independently of the write infrastructure.
- Complex Queries and Reports: If your UI requires data aggregated from multiple tables, a traditional normalized model leads to slow, complex
JOINs. With CQRS, you can create a pre-aggregated, denormalized read model in a document database (like MongoDB) or a search index (like Elasticsearch) that can serve this data instantly. - Task-Based UIs: When the user interface is more focused on performing actions rather than just editing data fields.
The Major Challenge: The biggest trade-off with CQRS is eventual consistency. Since the read model is updated after the write model, there will be a small delay (from milliseconds to seconds) before changes are visible. You must be able to explain this trade-off and its implications for user experience in an interview.
4. CQRS + Event Sourcing: The Power Couple
While powerful on their own, CQRS and Event Sourcing are a natural fit and solve each other's biggest weaknesses.

Here’s how they combine:
- The Write Side is an Event Sourcing system: The Command Model doesn't update a state table; it produces events and appends them to the Event Store.
- The Read Side is a consumer of these events: A "Projector" service subscribes to the stream of events and uses them to build and update the optimized read models.
This combination is a staple of modern, high-performance systems and is something you should feel comfortable drawing on a whiteboard.
5. Making the Choice: A Real-World FinTech Example
Knowing the theory is one thing; knowing when to apply it is what interviewers are looking for. The decision to use these complex patterns must be driven by concrete business and technical requirements.
Event Sourcing, CQRS and Micro Services: Real FinTech ...
This article from a consultant details the architecture of a real FinTech trading platform. It's a perfect case study that directly relates to your goals. It brilliantly explains the 'why' behind choosing ES and CQRS.
Read this article carefully. It is the most important resource for this lesson. Pay special attention to: The business drivers: auditability and scalability. Why Event Sourcing was chosen over alternatives for the auditability requirement. How they used a Proof of Concept (POC) to justify the complexity of CQRS for performance. The crucial insight that these patterns were applied only to specific services where they were needed, not everywhere.
6. The Decision Framework for Your Interview
Based on what you've learned, here is a framework to justify your data management strategy in a system design interview.
Question 1: What are the auditability and history requirements?
- High: "For the
TransactionServicein this trading platform, we have a legal requirement to maintain a perfect, immutable audit trail of all financial operations. Therefore, I would choose Event Sourcing. This gives us a complete history for compliance and allows for powerful temporal queries, like reconstructing a portfolio's state at any point in time." - Low: "For the
UserServicethat just manages user profiles, a simple CRUD model is sufficient. We only need the latest state, and an audit log isn't a primary business requirement."
Question 2: What are the read/write workload characteristics?
- Read-Heavy / Complex Queries: "The
DashboardServiceneeds to display complex analytics and reports, aggregating data from many sources. To ensure this is fast, I would apply the CQRS pattern. The write side would process incoming data, and the read side would maintain a denormalized document in MongoDB, pre-calculated for the dashboard. This avoids slow, complexJOINs on every page load." - Balanced / Simple Queries: "The
NotificationPreferencesServicehas balanced reads and writes and simple queries. A standard relational model with Spring Data JPA is the simplest and most effective solution here. CQRS would be over-engineering."
Question 3 (If you chose CQRS/ES): How do you handle the complexity?
- Justify the Cost: "I recognize that CQRS adds complexity and introduces eventual consistency. In the case of the dashboard, a few hundred milliseconds of data lag is an acceptable trade-off for a 10x improvement in load time. For the trading transaction service, the legal requirement for auditability makes the complexity of Event Sourcing non-negotiable."
- Apply Selectively: "Crucially, I would not apply these patterns to every service. They would be used strategically only on the services whose requirements justify the added architectural overhead, as we saw in the FinTech example."
Test your understanding!
You are designing an e-commerce platform. Consider two services:
- Order Service: Manages customer orders, including creation, status updates (e.g.,
PAID,SHIPPED,DELIVERED), and returns. - Product Catalog Service: Manages product information, including descriptions, prices, and reviews. Millions of users browse the catalog, but product information is only updated by a small team of employees.
Which data management strategy would you choose for each service, and why?
Show answer
-
Order Service: This is a prime candidate for Event Sourcing (and likely CQRS as well).
- Justification: The lifecycle of an order is a natural sequence of events (
OrderPlaced,PaymentProcessed,OrderShipped,OrderDelivered). Storing this as an event stream provides a perfect, immutable audit history, which is vital for customer service (e.g., "What happened to my order?"), dispute resolution, and business analytics. While a simple state machine could work, ES is far more robust and provides a rich history "for free."
- Justification: The lifecycle of an order is a natural sequence of events (
-
Product Catalog Service: This is a classic use case for CQRS.
- Justification: This service is extremely read-heavy (millions of users browsing) and write-light (infrequent updates by staff). A single model would create contention.
- Command Side: A simple relational database to allow staff to update product details.
- Query Side: A highly optimized, denormalized read model stored in a search engine like Elasticsearch. This would provide ultra-fast, faceted search capabilities for users, which would be very difficult to achieve with a standard relational database. The eventual consistency (a few seconds for a price update to appear) is a perfectly acceptable trade-off.
- Justification: This service is extremely read-heavy (millions of users browsing) and write-light (infrequent updates by staff). A single model would create contention.
7. Conclusion
You've now explored some of the most powerful—and most frequently misunderstood—patterns in microservices architecture. Being able to intelligently discuss them is a hallmark of a senior engineer.
Key Takeaways:
- Start Simple: Default to a standard CRUD model unless a service's specific requirements force you to consider something more complex.
- Event Sourcing for Auditability: When you need an infallible history of every change, ES is the gold standard. The primary driver is often business or legal compliance.
- CQRS for Performance at Scale: When read and write patterns diverge significantly, or when you need highly optimized read models, CQRS is your tool.
- Justify the Trade-offs: Always acknowledge the complexity and eventual consistency introduced by these patterns and explain why the benefits outweigh the costs for a specific service.
In our next lesson, we will zoom out from individual services and look at the "platform" level. We will explain how a service mesh (e.g., Istio) enhances observability, security (mTLS), and traffic management, providing these capabilities without needing to bake them into every single service.
Can't find a good explanation? Sign up and we'll make it for you
Sign up