Overview

3 Encoding Semantics in the Type System

In this chapter, the central idea is that good modeling starts by asking what data actually means in the domain, not just what it looks like in JSON or code. By repeatedly probing the meaning of fields like elapsed days, contact angle, and sample ID, the text shows how to uncover hidden assumptions, discover invariants, and distinguish real domain concepts from incidental serialization details. That understanding becomes the foundation for writing software that is correct by construction rather than merely well-formed.

The chapter then shows why documentation and descriptive names help but are not enough on their own. Validation in constructors can prevent some invalid values from being created, but if the underlying representation is still too generic, the meaning is easily lost once data is read back out and passed around the program. The key insight is that types should reflect the actual sets of values a domain concept can take, so the compiler can preserve semantics across transformations instead of leaving correctness up to human memory and discipline.

Using this lens, the text argues for introducing more precise types such as non-negative integers, bounded degrees, enums for fixed categories, and composite types for structured identifiers. It also warns that there is a balance to strike: overly generic types create ambiguity and bugs, while overly specialized ones can create unnecessary friction and force architectural boundaries. The overall message is that thoughtful use of the type system improves safety, clarity, and communication, and often pays for itself by eliminating entire classes of misunderstandings before they become defects.

The basics of drying oils
Conflicting meanings between our data and the type we’ve chosen to model it
Flexibility in representation forces stricter boundaries at the edges of our programs
more conflicting meanings between our type and data
Sending very mixed signals
This curve is entirely made up, but how I generally think about things. “More types” = “more better” (up to a point)

Summary

  • The most important part of our job is getting to the bottom of what data means
  • We have to go outside of our programs to find data’s meaning. Inside we can only model it
  • Understanding what the data in a domain means is fundamental to writing good software
  • Simple questions, applied thoughtfully, can help us explore a complex domain
  • When we put data’s meaning into code, it can prevent us from making errors
  • Documentation, comments, and variable naming are useful, but they cannot enforce correctness or meaning on their own
  • Data types are where we encode the semantics of the domain.
  • Putting validation code in the constructor ensures only correct data can be created
  • Types have meaning just like data.
  • We explore the meaning of a type by visualizing the concrete set of values it denotes
  • Comparing meanings is a powerful tool for checking if our modeling is sound
  • There’s a sweet spot for typing rigor. Too many types is obnoxious, too few is dangerous
  • Good code should make doing the wrong thing very hard (or impossible) to do
  • Code which relies on all developers to share the same unstated opinion about the “obvious” meaning of an ambiguous type should be refactored to make the “obvious” explicit
  • The JVM is extremely efficient. The performance impact of adding more types is seldom an issue
  • Always pay caution to strings. They make it easy to accidentally hide aspects of a domain

FAQ

What is the main idea of this chapter?The chapter explains that good modeling starts by understanding what data means, then encoding that meaning as constraints and invariants in Java’s type system. When the type matches the domain meaning, code becomes safer, clearer, and harder to misuse.
Why does the chapter begin by asking “What does it mean?”Because understanding a data element’s meaning is the foundation for modeling it correctly. By repeatedly asking what something is, you uncover important domain facts, constraints, and invariants that should shape the code.
Why isn’t mechanically translating JSON fields into Java types enough?Because matching shape alone does not capture semantics. A field like a string or number may hide richer meaning, such as units, valid ranges, or composite concepts, and those need to be modeled explicitly.
What was wrong with representing daysElapsed as a plain int?A plain int allows negative values, but the domain only permits zero or positive elapsed days. A dedicated type such as NonNegativeInt better matches the domain and prevents invalid states.
Why is documentation or better variable naming not enough to enforce correctness?Documentation and names can help humans, but they do not stop invalid values from being created. The code still accepts nonsense unless the type system or runtime checks enforce the invariant directly.
What problem does validating values in a record constructor solve?It prevents invalid objects from being created in the first place. For example, constructor checks can reject negative days or out-of-range angles so the object is always valid after construction.
Why does a validated String still feel like a weak model for sampleId?Because the meaning is still hidden inside a generic string. Even if the format is validated, the code must still parse and interpret the string everywhere, which causes information leakage and loss of semantic clarity.
How does modeling sampleId as a composite type improve the design?By splitting it into meaningful parts like CuringMethod and NonNegativeInt, the program retains semantic information at the type level. This removes string parsing from unrelated code and makes grouping and transformation easier and safer.
What does it mean that “types denote sets of values”?It means a type represents the collection of values it can legally hold. If the set of values allowed by the type is much broader than the domain allows, the model is a mismatch and bugs become easier to create.
Why are new domain-specific types worth the effort?They improve correctness, readability, and maintainability by making illegal states harder or impossible to represent. Although they add some upfront boilerplate, they often reduce far more costly mistakes later, including misunderstandings about units, ranges, and meanings.

pro $24.99 per month

  • access to all Manning books, MEAPs, liveVideos, liveProjects, and audiobooks!
  • choose one free eBook per month to keep
  • exclusive 50% discount on all purchases
  • renews monthly, pause or cancel renewal anytime

lite $19.99 per month

  • access to all Manning books, including MEAPs!

team

5, 10 or 20 seats+ for your team - learn more


choose your plan

team

monthly
annual
$49.99
$499.99
only $41.67 per month
  • five seats for your team
  • access to all Manning books, MEAPs, liveVideos, liveProjects, and audiobooks!
  • choose another free product every time you renew
  • choose twelve free products per year
  • exclusive 50% discount on all purchases
  • renews monthly, pause or cancel renewal anytime
  • renews annually, pause or cancel renewal anytime
  • Data-Oriented Programming in Java ebook for free
choose your plan

team

monthly
annual
$49.99
$499.99
only $41.67 per month
  • five seats for your team
  • access to all Manning books, MEAPs, liveVideos, liveProjects, and audiobooks!
  • choose another free product every time you renew
  • choose twelve free products per year
  • exclusive 50% discount on all purchases
  • renews monthly, pause or cancel renewal anytime
  • renews annually, pause or cancel renewal anytime
  • Data-Oriented Programming in Java ebook for free