Decode: errors as values, not warnings
The Nest reflex for a missing row is throw new NotFoundException(). Fusion models failure as data, and two of Rai’s reviews pushed exactly on that shift.
The comment (Sergii Volodko, PR #401, on GetFlights.cs):
“We shouldn’t consider all errors as warnings. Instead, I’d introduce a new error type, like
FlightNotFound, and then when catching errors on DB access layer produce those errors in result, after that on the application level, we can distinguish them by type and place into warnings.”
And (Sergii, same PR, on GetFlightsResponse.cs):
“a small design smell here, Response is currently an API presentation term, but we add it here on the application level … instead of introducing intermediate nested classes like this one, we need to create an extension of our
Result:ResultWithWarnings?”
What he meant. Two things. First, typed errors carry domain meaning. When a DB read fails, don’t flatten it into a generic “warning”; return a typed error (FlightNotFound) that a caller can pattern-match to decide a 404 versus a 504 versus a soft warning. The distinction the domain cares about should live in the type system, not in a status string or a boolean. Second, don’t let a layer’s vocabulary leak downward. Response is a presentation word; naming an application-layer type Response mixes the layers. Express the concept as a domain-level Result extension instead. That’s the ubiquitous-language discipline (Module 8’s Result, Module 11’s naming) applied to errors.
// What Sergii pushed against: every failure becomes an untyped warning.
result.Warnings.Add("could not load flight");
// The shift: a typed error the endpoint can map by type (Module 5's switch).
public sealed record FlightNotFound(string Field, string Message) : EjError(Field, Message);
return Result<FlightsView>.Failure(new FlightNotFound(nameof(key), "No flight for key."));The convention doc (D5/E2, from Nick and Sergii on earlier PRs) states the downstream rule:
“Branch on Result type, not domain status values. Endpoints use
result.IsSuccessand pattern-match on error types (EntityNotFound,DecisionNotFound). They never inspect domain-specific status strings likeresult.Status == \"reverted\".”
Try it yourself
Why a typed error beats a warning
Explain Sergii's push in DDD terms.
Sergii asked Rai to introduce a FlightNotFound error type instead of treating every DB-access failure as a warning. What does the typed error let a caller do that a generic warning does not?
Reveal answer
A typed error (FlightNotFound : EjError) lets the caller pattern-match on the type and choose the right response: a 404 for not-found, a 504 for a timeout, a warning for a partial result. Collapsing everything into 'a warning' throws away the distinction the domain cares about. The type carries the meaning, so the discrimination lives in the type system rather than in string parsing or status flags.
The layering smell in a name
Sergii flagged an application-layer class named GetFlightsResponse and suggested a Result extension instead. What was the smell?
Show answer
Correct answer: D — Response is a presentation/API word leaking into the application layer
Response is presentation-layer language. Putting it on an application-layer type mixes vocabularies across a boundary. Sergii wanted the concept expressed as a domain-level Result extension (ResultWithWarnings), keeping each layer's names in its own layer. It's ubiquitous language applied to error handling.