Error Modeling
Failure as part of the design: separating expected business failure from validation, dependency failure and outright bugs, and choosing how each is expressed in types.
Failure is part of the design, not an appendix to it. Expected business failure, validation failure, dependency failure and programming bug are four categories with four different correct responses.
Six kinds — InvalidInput, NotFound, Conflict, Unauthorized, DependencyTimeout, InternalBug — chosen because each one gets a different response. The taxonomy is a type-level decision, not a status-code table.
`Result<Payment, PaymentError>` puts expected failure in the return type, where the compiler can insist somebody deals with it. What that costs depends enormously on the language.
A non-local jump is exactly right for a failure nobody local can answer, and exactly wrong for an outcome the caller was supposed to decide about. The dividing line is not a rule about exceptions.
Every failure has a point where it stops being handled locally and becomes somebody else's problem. Choosing that point deliberately is a design decision; discovering it in production is not.
`catch {}` is the visible version. The interesting one is an interface that can only return success or failure, so the code that half-worked has nowhere honest to put the truth.