Whetstone.
Decode your own reviews"It reads more like a value object"
Module 8 · Lesson 112 min

"It reads more like a value object"

This module is the payoff. You’ve learned the concepts and the Fusion mechanics; now here are the real comments you got on real PRs, with who said them and why, so the abstractions land on the exact moments you met them. We start with the richest one.

On PR #508 (the per-flight notes work), you had modelled a flight note as an aggregate root with its own int Id. Mustafa’s comment, on domain/flight-notes/FlightNote.cs:

This is the identity litmus test from Module 1, Lesson 3, applied to a live decision. Ask the question about the note: two notes with the same flight-key and the same body, are they the same note or two different notes you need to track? They’re the same. A note is addressed through its flight, not through an id of its own. By the test, that’s a value object, not an entity, and certainly not an aggregate root with its own identity.

Notice the second half of the comment, because it’s a general lesson about justifying design. The original doc-comment defended the note’s surrogate identity by pointing at a future “group note” feature. Mustafa’s move: group notes are descoped, so that rationale can go. You can’t hold present complexity up with a feature that isn’t coming. When a design’s justification rests on speculative future work, and that work gets cut, the justification evaporates and the design should follow.

And there’s a payoff to getting the classification right that the comment flags: once the domain type is FlightNoteVo, the persistence row is free to take the clean name FlightNote, instead of an awkward FlightNoteRow/DomainFlightNote alias dance. The right domain classification simplifies the persistence naming. Good modelling pays rent downstream.

You’ll notice you didn’t argue this one, you took it and reshaped the model, which was right. The lesson to carry forward isn’t “trust Mustafa,” it’s “run the litmus test at design time so the reviewer doesn’t have to.” The next lesson is what fell out of this reclassification: because the note became a value object, and value objects are immutable, the whole persistence strategy changed.

Practice

Try it yourself

Recall

Why the note was a value object

Reconstruct the reviewer's reasoning from the identity test.

Mustafa said the flight note should be a value object, not an aggregate root. What was the domain reason, in terms of the identity litmus test?

Reveal answer

A note has no meaningful domain identity: it's addressed through its flight (via the flight key), not through an id of its own. Two notes with the same flight-key and body are the same note, there's nothing to track independently. By the litmus test that's a value object. The int Id you gave it was a persistence concern (the row needs a PK), not a domain identity, so modelling it as an aggregate root manufactured identity that wasn't there.

Quiz

The rationale that expired

Part of the note's aggregate justification was a future "group note" feature. Why did the reviewer say that rationale had to go?

  1. AGroup notes shipped on schedule, so the original justification still held
  2. BGroup notes are a frontend concern
  3. CThe reviewer was wrong to raise it
  4. DGroup notes were descoped, so a justification resting on them no longer holds
Show answer

Correct answer: D — Group notes were descoped, so a justification resting on them no longer holds

The doc justified the note's surrogate identity by pointing at a future group-note feature. Once group notes were descoped, that rationale evaporated: you can't justify present complexity with a feature that isn't coming. Design to what's real now, not to a speculative future that may never arrive.

Recall

How you'd design it next time

Turn the lesson into an up-front instinct.

Next time you model a new concept that hangs off an existing entity, what's the first question to ask so you don't repeat this?

Reveal answer

Ask the identity litmus test before reaching for an aggregate: 'does this thing have identity of its own, or is it addressed through its owner?' If it's addressed through its owner (a note through its flight), it's a value object; give it no domain id, and treat any surrogate key as a persistence-only concern. Default to value object; only promote to entity/aggregate when the business genuinely needs to track this thing independently over time.

Sign in to track your progress →