The Limits of My Language: Navigating Data Models (Designing Data-Intensive Applications Chapter 3)

In the previous posts in this series, we looked at the high-level architectural trade-offs and nonfunctional requirements that define modern systems. In Chapter 3 of Designing Data-Intensive Applications (Second Edition), "Data Models and Query Languages," the authors dive into what is perhaps the most critical part of software development: how we represent data. 

As the chapter’s opening quote from Ludwig Wittgenstein suggests, "The limits of my language mean the limits of my world". The data model we choose doesn't just dictate how we write code; it dictates how we think about the very problems we are trying to solve.

The Layers of Abstraction

Modern applications are built by layering data models. As a developer, you might model the real world (people, goods, money flows) as objects or data structures in your code. To store those, you use a general-purpose data model like JSON documents, relational tables, or graph vertices. Below that, database engineers decide how to represent those models as bytes on disk or in memory, and hardware engineers represent those bytes as electrical currents or magnetic fields. Each layer hides the complexity of the one below it, providing a clean abstraction that allows different teams to work together effectively.

The Relational vs. Document Debate

For decades, the relational model (SQL) has been the dominant way to represent data, but the rise of the document model (NoSQL) has offered a major alternative.

  • The Impedance Mismatch: Many developers prefer the document model because it reduces the "impedance mismatch", the awkward translation layer required between objects in application code and the tables, rows, and columns of a relational database.
  • Locality vs. Joins: JSON documents have better data locality; if you need to load a user profile and all its associated data (like a LinkedIn resume), a single document fetch is often faster than the "messy multiway join" required in a relational schema.
  • Schema Flexibility: Document databases are often called "schemaless," but the authors clarify they are actually schema-on-read (the structure is implicit and assumed by the code) compared to the schema-on-write (explicitly enforced by the database) nature of relational systems.

Normalization and Relationships

The choice between these models often comes down to the types of relationships in your data:

  • One-to-Many: Documents are excellent for "one-to-few" or tree-like structures.
  • Many-to-One and Many-to-Many: These relationships do not fit neatly into a single JSON document. Normalization (referencing entities by ID) is generally preferred here to avoid data redundancy and ensure that updates, like changing a company logo, only need to happen in one place. 

When Data Becomes a Graph

If your data has complex many-to-many relationships, it becomes more natural to model it as a graph. Chapter 3 explores two main graph models: property graphs (used by databases like Neo4j) and triple-stores. 

Graphs are highly evolvable; as you add new features, you can easily extend the graph to accommodate new types of vertices and edges. The chapter introduces several query languages for these models, including Cypher (which uses a concise "arrow" notation for patterns) and SPARQL.

Beyond Traditional CRUD: Event Sourcing

The authors also introduce event sourcing, a model where the "system of record" is an immutable, append-only log of events. In this architecture, you never update or delete data directly. Instead, you derive read-optimized materialized views from the event log using a principle called Command Query Responsibility Segregation (CQRS). This is particularly powerful for complex business domains where you need a clear audit log of why state changes occurred.

Conclusion: No One Model to Rule Them All

Chapter 3 emphasizes that some queries are easy in one model and "awkward" in another. While the relational model remains essential for analytics and data warehousing (often using star or snowflake schemas), alternatives like documents, graphs, and event logs have become popular for specialized needs. The goal is to develop a strong intuition for these trade-offs so you can combine these tools into a solid application architecture.


Reference 

Designing Data-Intensive Applications: The Big Ideas Behind Reliable, Scalable, and Maintainable Systems
Book by Martin Kleppmann
and Chris Riccomini

This blog post is a summary of my personal notes and understanding from reading "Designing Data-Intensive Applications" by Martin Kleppmann. All credit for the original ideas belongs to the author. 


Comments