Event Logs, CQRS, Materialized Views, and Why One Dataset Often Needs Multiple Shapes
One of the most important architecture ideas in data work is also one of the easiest to miss: the best shape for writing data is often the wrong shape for reading it.
Teams run into this when they try to make one representation serve every need at once.
The write path wants correctness, validation, and a durable source of truth. The product UI wants fast read models. Analytics wants wide historical scans. Machine learning wants matrix-like numerical features. API clients want response payloads shaped exactly for one screen.
Those are different jobs. Trying to force them into one universal model usually creates friction somewhere.
This article connects a few ideas that are often taught separately: event sourcing, CQRS, materialized views, GraphQL response shaping, star and snowflake schemas, and DataFrame-style analytical transformations. The unifying point is simple: one dataset often needs multiple shapes because different questions demand different representations.
The Source of Truth Is Not Always the Best Thing to Query
Suppose you are building a conference platform.
Attendees register, cancel, switch tickets, get seat assignments, request invoices, and sometimes move between sessions. The organizer wants a dashboard. Attendees want a booking confirmation. Support wants an audit trail. Finance wants settlement reports.
You can already see the mismatch.
The write path needs a reliable way to record what actually happened. The attendee page wants one coherent booking summary. The organizer dashboard wants trends and counters over time. Finance wants event history grouped by money flows.
One canonical table can start this journey. It rarely finishes it cleanly.
Event Logs Store What Happened, Not Just What Is True Now
An event log records facts in append-only form.
Instead of storing only the latest state, it stores events such as:
conference_createdregistrations_openedseats_reservedbooking_paidbooking_canceledseat_reassigned
This is powerful because the log preserves history and ordering. You do not only know the current state. You know how that state came to exist.
That distinction matters whenever the sequence of changes affects meaning.
In the conference example, you cannot sensibly process "booking canceled" before "booking created." The order is part of the truth.
An event log makes that ordering explicit.
Event Sourcing Treats the Log as the Durable Truth
With event sourcing, the durable source of truth is the event log itself. Current state is derived by replaying or processing those events.
That buys several benefits.
First, the event names often describe the business more clearly than raw row mutations. "Booking canceled" is more meaningful than "set active = false and decrement seat count." The intent is explicit.
Second, derived views can be rebuilt. If a read model has a bug, you can fix the projection logic and replay the same events to compute a corrected view.
Third, multiple views can be derived from the same history:
- one for customer-facing booking confirmations,
- one for organizer capacity charts,
- one for badge-printing queues,
- one for financial reconciliation,
- one for audit or compliance needs.
That is the deeper architectural value. The same source facts can feed several optimized read models.
CQRS Makes the Split Explicit
Command query responsibility segregation, or CQRS, is the pattern of separating the write model from the read model.
The write side validates commands and records the accepted facts. The read side exposes query-optimized representations.
This does not require event sourcing, but event logs pair with CQRS naturally because the log becomes the stable input from which read models are derived.
The key architectural insight is that reads and writes often want different shapes.
The write side might want:
- strict invariants,
- small transactional updates,
- durable ordering,
- explicit business rules.
The read side might want:
- prejoined data,
- counters and summaries,
- denormalized structures,
- search-oriented indexes,
- latency-optimized materialized views.
If you force one schema to satisfy both perfectly, you usually compromise both.
Materialized Views Are Computed Read Models
A materialized view is a stored representation of data that has already been transformed for a particular read path.
That matters because many product queries are expensive if computed from scratch every time.
A home timeline, an activity feed, a dashboard summary, or a booking confirmation page can all be treated as read models. Instead of rebuilding them from the base facts on every request, you update the materialized view when new events arrive.
That is the same core move behind many familiar systems:
- feed fan-out,
- cached counters,
- search indexes,
- derived analytics tables,
- precomputed notification lists.
The advantage is faster and simpler reads.
The cost is that derived views can lag, drift, or need reprocessing logic when the projection changes.
Reprocessing Is a Feature, but It Has Sharp Edges
A major strength of event-driven read models is reproducibility. If a projection is wrong, you can often delete the view and rebuild it from the same event history.
That is enormously useful.
But it also creates operational constraints.
Some events depend on external information that changes over time. If an event stores an amount in one currency and the conversion rate must come from a third-party service, replaying later may not produce the same result unless the relevant exchange rate is captured or reproducible.
Some systems also trigger external side effects such as emails, webhooks, or billing actions. Replaying events must not accidentally resend those effects.
This is one reason event processing design requires care. Rebuildable read models are powerful, but only if the distinction between internal state derivation and external side effects stays clear.
Immutability Helps Auditability, but It Complicates Deletion
Append-only logs have another tradeoff that matters more as products mature: privacy and data retention.
If personal data is embedded directly in immutable events, deleting or correcting it becomes hard. That is not just a storage inconvenience. It is a product and legal risk.
This is where architectural discussions need to include privacy early.
Good event modeling sometimes means:
- storing references instead of raw personal data where possible,
- separating sensitive payloads from the immutable event history,
- planning deletion or crypto-shredding strategies,
- being careful about which fields truly belong in irreversible logs.
This is not secondary to architecture. It is part of the architecture.
GraphQL Shows That Clients Want Query-Specific Shapes
GraphQL is often discussed as an API choice, but it also reinforces the same modeling lesson.
Clients rarely want a perfectly normalized response. They want a response shaped for rendering.
A chat interface may ask for:
- channel name,
- the latest messages,
- sender names and avatars,
- reply preview text,
- timestamps,
- exactly enough nested structure to render one screen.
That response may duplicate some information, such as sender details repeated across messages, because the client cares about easy consumption more than storage purity.
This is a read-model mindset.
GraphQL does not require event sourcing or CQRS, but it expresses the same product truth: query consumers want data shaped for the job at hand.
Analytics Uses Different Shapes for the Same Reason
The same principle shows up in analytics.
Operational systems usually care about transaction correctness. Analytical systems care about scanning large histories to answer questions across time, products, regions, campaigns, or customer segments.
That is why data warehouses often use fact and dimension models.
A fact table stores events or measurements such as purchases, page views, or bookings.
Dimension tables store descriptive context such as:
- product,
- customer,
- date,
- store,
- promotion,
- geography.
This shape is not mainly about object purity. It is about making analytical queries practical.
Star and Snowflake Schemas Are Read Optimizations
In a star schema, the fact table sits at the center and references dimensions around it. In a snowflake schema, some dimensions are further normalized into subdimensions.
These patterns exist because analysts repeatedly ask questions like:
- sales by month,
- revenue by region,
- conversion by campaign,
- bookings by conference and ticket type.
The data is shaped to answer those questions efficiently.
That may involve denormalization that would feel awkward in a pure OLTP design. In analytics, that can be a good trade because updates happen differently and the cost model is different.
This is a reminder that normalization versus denormalization is not one eternal rule. It depends on the workload.
Some Analytical Work Wants Tables, Other Work Wants Matrices
Once you move from business reporting into statistical analysis or machine learning, even table-shaped data can become an intermediate form rather than the final one.
DataFrames let analysts filter, group, join, reshape, and derive new columns in a workflow that is closer to computation than to transactional query serving.
Sometimes the next step is turning relational data into matrices or arrays.
For example:
- users by products,
- time series by interval,
- one-hot encoded categories,
- feature vectors for ranking or prediction models.
That shape would be strange for a product database. It is perfectly natural for analysis and model training.
So the pattern repeats again: the same underlying facts get reshaped because the question changed.
Frontend Systems Already Live on Derived Data
This entire topic is more relevant to frontend engineers than it first appears.
Most product UIs do not read directly from the raw source of truth in its most canonical form. They read from some projection of it:
- a search index,
- a recommendation service,
- a cached aggregate,
- a GraphQL response,
- a denormalized activity stream,
- a dashboard metric table,
- an eventually consistent read replica.
That has product consequences.
If a view is derived, it may be stale. If it is materialized, it may lag. If it is rebuilt from events, it may need careful copy in the UI when certainty is delayed. If it depends on denormalized context, there may be moments when a profile rename shows up in one surface before another.
Understanding that helps frontend teams design honest states instead of pretending every page is always showing the most current canonical truth.
When Multiple Shapes Are Worth the Complexity
Not every system needs event sourcing or CQRS.
If the product is simple, the data volume is modest, and the read patterns are straightforward, one well-designed relational schema may be enough.
The complexity becomes worth it when several of these are true:
- history and auditability matter,
- multiple read patterns are expensive to compute live,
- product surfaces need different projections of the same facts,
- analytics or machine learning needs diverge sharply from OLTP,
- rebuildable derived views would reduce operational risk,
- the organization needs clearer separation between command validation and query serving.
In other words, multiple shapes are justified when one shape is clearly doing too many incompatible jobs.
Conclusion
One dataset often needs multiple representations because different consumers ask fundamentally different questions.
Event logs preserve what happened. Event sourcing treats that history as the durable truth. CQRS separates the write model from the read model. Materialized views optimize product queries. GraphQL shows how clients want response-specific shapes. Star and snowflake schemas optimize analytical questions. DataFrames and matrices reshape the same facts again for exploration and machine learning.
The common lesson is not that every team needs every pattern. It is that data shape should follow query shape. Once you accept that, architecture becomes less about finding one perfect schema and more about designing the right projections for the work each part of the system actually needs to do.
