Whetstone.
Decode your own reviews"Don't consider all errors as warnings"
Module 8 · Lesson 412 min

"Don't consider all errors as warnings"

Now to Sergii, and the errors-as-values concept from Module 1, Lesson 5, as it showed up in your review. On PR #401 (partial results for GetFlights), you’d treated failures uniformly, folding everything into “warnings.” Sergii’s comment on application/flights/GetFlights.cs:

This is the typed-errors point from the foundations lesson, made concrete. Collapsing every failure into one generic “warning” throws away the distinction the domain cares about. Is it a flight that genuinely doesn’t exist? A timeout? A permissions problem? Once they’re all “a warning,” nobody downstream can tell, and nobody can respond differently. Sergii’s fix is to lift the distinction into the type system: a FlightNotFound type, produced where the failure actually happens (the DB layer), and pattern-matched at the application layer to decide what it means.

There was a second comment on the same PR, on GetFlightsResponse.cs, and it’s a layering point hiding in a naming complaint:

Response is a presentation word: it belongs to the API layer, the thing that talks HTTP. You’d introduced it in the application layer. That leaks presentation vocabulary inward, which is both a ubiquitous-language smell (the wrong word for the layer) and a layering smell (an inner layer reaching for an outer layer’s concept). Sergii’s fix expresses the idea where it belongs: a domain-level Result extension, ResultWithWarnings, so the concept “a success that carries non-fatal warnings” lives in the domain’s own language.

The convention doc (D5/E2, distilled from Nick and Sergii across #272/#251) states the endpoint-side rule that follows:

Sergii’s feedback is a good example of the meta-note in the dossier: your replies to it were solid reasoning, you just arrived at the typed-error design in review rather than at design time. The habit to build is asking, before you write the happy path: what are the distinct ways this can fail, and does each deserve its own type? The next lesson is Nick’s, and it’s the anaemic-domain trap you learned in the abstract, caught in your actual code.

Practice

Try it yourself

Recall

What Sergii asked you to lift

The core move behind the comment.

You'd collapsed several distinct failures into generic "warnings." What did Sergii want you to do instead, and what DDD principle is that?

Reveal answer

Introduce typed errors (like FlightNotFound) so the different kinds of failure are distinct types, not one undifferentiated bucket. Produce them at the DB-access layer, then at the application level distinguish them by type and decide (warning vs hard error). It's the errors-as-values principle sharpened: lift the distinction the domain cares about into the TYPE system, so callers pattern-match the kind of failure instead of losing it.

Quiz

The layering smell in the naming

Sergii also flagged a type named Response living in the application layer. Why was that a smell?

  1. AResponse is too long a name
  2. BThe application layer isn't allowed to define classes
  3. CIt should have been an interface
  4. DResponse is a presentation/API term leaking into the application layer
Show answer

Correct answer: D — Response is a presentation/API term leaking into the application layer

Response is an API/presentation word. Naming an application-layer type Response leaks presentation vocabulary into an inner layer, a ubiquitous-language and layering smell. Sergii wanted the concept expressed as a domain-level Result extension (a ResultWithWarnings), keeping the layer's language clean.

Recall

The reflex versus the idiom

Translate the habit.

For a missing flight, what's the Nest reflex, and what's the Fusion idiom?

Reveal answer

Nest reflex: throw new NotFoundException() and let a filter map it to a 404. Fusion idiom: return Result.Failure(new EntityNotFound(...)), and the endpoint maps the error TYPE to the 404. The failure is a typed value that flows through the pipeline, and the caller decides its HTTP meaning by pattern-matching the type, not by catching an exception.

Sign in to track your progress →