From 536524f4a5c40e6cf2d0c38a00bd70fad2abc319 Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 15 Jul 2026 23:50:26 +0000 Subject: [PATCH] docs: expand and reorder the FAQ into a decision gateway MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Turn the FAQ from a concept-clarifier into a page that answers the real adoption objections a newcomer has. Add four practical questions: - Does FirstClassErrors replace logging? (no — it structures errors; the logging system records occurrences) - Can I adopt FirstClassErrors incrementally? (yes — domain or use case at a time, no global migration) - How do I handle an exception from a third-party library? (model it at the boundary when it is a stable failure; do not first-class every one) - Can error messages be shown to users? (ShortMessage/DetailedMessage are the controlled public messages; DiagnosticMessage stays internal) Reorder the questions into three implicit movements: why use the library, choosing between exceptions/Outcome/technical errors, then documenting and diagnosing. Sharpen a few answers: - Say the library attaches a structured Error to the exception, rather than "enriches the Error carried by" it (the Error is not a standard field of a .NET exception). - Scope the documentation rule to "every first-class error you define". - Give the concrete factory benefit over new: it avoids repeating codes, messages, and metadata across use cases. - Rename the domain-nesting question to "How do I nest the different error categories?" and link the dedicated taxonomy page. The third-party-exception answer states that the first-class error captures the failure's meaning and does not store the caught exception object: DiagnosableException carries only an Error, and Error.InnerErrors nests Errors, not exceptions. The English and French pages stay in sync. --- doc/FAQ.en.md | 94 +++++++++++++++++++++++++++++++++------------------ doc/FAQ.fr.md | 94 +++++++++++++++++++++++++++++++++------------------ 2 files changed, 122 insertions(+), 66 deletions(-) diff --git a/doc/FAQ.en.md b/doc/FAQ.en.md index 553c9e4..7dd76f5 100644 --- a/doc/FAQ.en.md +++ b/doc/FAQ.en.md @@ -7,7 +7,7 @@ You can. FirstClassErrors still uses standard .NET exceptions as the mechanism that signals and propagates failures. -The library enriches the `Error` carried by that exception with a stable code, structured context, diagnostics, and linked documentation. See [Core Concepts](CoreConcepts.en.md). +FirstClassErrors attaches a structured `Error` to that exception — carrying a stable code, structured context, diagnostics, and linked documentation. See [Core Concepts](CoreConcepts.en.md). ## Why not use a generic `Result`? @@ -17,18 +17,62 @@ You could. Carrying the library’s `Error` in a general-purpose result type — See [Usage Patterns](UsagePatterns.en.md) and [Comparison with error-handling libraries](ComparisonWithOtherLibraries.en.md). +## Does FirstClassErrors replace logging? + +No. It structures errors and their documentation; your logging system records their occurrences and runtime context. A first-class error gives each logged occurrence a stable code and a shared explanation, but it neither stores nor replaces the log itself. + +See [Integrate with structured logging](LoggingIntegration.en.md). + ## Is this too heavy for a simple application? It can be. Small scripts, prototypes, and systems without long-term support needs may be better served by standard exceptions. See [When Not to Use FirstClassErrors](WhenNotToUseFirstClassErrors.en.md) for the decision criteria. +## Can I adopt FirstClassErrors incrementally? + +Yes. You do not need a global migration. Introduce it where errors are worth modeling — one domain, module, or use case at a time — and leave the rest on standard exceptions until they earn a first-class error. Because a factory is just a typed way to build an `Error`, existing code keeps working while new or reworked paths adopt the model. + +See [When Not to Use FirstClassErrors](WhenNotToUseFirstClassErrors.en.md). + +## When should I use `Outcome`? + +Use it when failure is an expected branch of normal flow, such as validation, parsing, batch processing, or partial success. + +Use an exception when the failure should interrupt the operation at that level. Both paths can carry the same `Error` created by the same factory. + +See [Usage Patterns](UsagePatterns.en.md). + +## Does `Outcome` preserve a stack trace? + +It does not create or throw an exception while the error is carried as data. If the failure is later escalated with `GetResultOrThrow()` or `error.ToException()`, the exception and its stack trace start at that escalation point. + +## Should every exception become a first-class error? + +No. Model the meaningful application errors: recognized situations, rules, constraints, or boundary failures that benefit from a stable identity and a shared explanation. Framework exceptions, accidental crashes, and low-level implementation faults usually stay as plain technical exceptions. + +See [When Not to Use FirstClassErrors](WhenNotToUseFirstClassErrors.en.md). + +## How do I handle an exception from a third-party library? + +Catch it at the boundary — typically an adapter or secondary port — and decide whether it represents a stable application failure. If it does, model it with a factory as an `InfrastructureError` (or a `SecondaryPortError` for an outgoing dependency, a `PrimaryPortError` for an incoming one), put the technical detail in the `DiagnosticMessage`, and add safe facts through `ErrorContext`. + +The first-class error captures the *meaning* of the failure; it does not store the caught exception object. Keep the original exception where it belongs — recorded by your logging pipeline at the catch site. Do not turn every technical exception into a first-class error: only the boundary failures that deserve a stable identity. + +See [Error Taxonomy and Composition](ErrorTaxonomy.en.md) and [When Not to Use FirstClassErrors](WhenNotToUseFirstClassErrors.en.md). + ## Why use error factories instead of `new`? -A factory gives one error situation a name, centralizes its code and messages, keeps construction out of the happy path, and acts as the anchor for living documentation. +A factory gives one error situation a name, centralizes its code and messages, and acts as the anchor for living documentation. Compared with a `new DomainError(...)` at each call site, it avoids repeating codes, messages, and metadata across use cases, and keeps error construction out of the happy path. See [Getting Started](GettingStarted.en.md). +## Should I document every first-class error? + +Yes — every first-class error you define is meant to be documented. An undocumented error never reaches the generated catalog, and the analyzer [FCE009](analyzers/FCE009.en.md) flags any error factory you leave without documentation. + +See [Writing Error Documentation](WritingErrorsGuide.en.md). + ## What is the difference between error documentation and runtime messages? Documentation is the part of an error that does not depend on any single occurrence: it is identical for every instance and never changes at runtime. It exists to help you *understand* the error — title, meaning, rule, diagnostic hypotheses, and representative examples. @@ -41,21 +85,13 @@ Runtime messages are carried by the error instance itself and help you *investig See [Writing Error Documentation](WritingErrorsGuide.en.md) and [Writing Error Messages](WritingErrorMessages.en.md). -## Are diagnostics the same as root causes? - -No. Diagnostics are plausible hypotheses and investigation starting points. They describe what may explain the error without claiming certainty or assigning blame. +## Can error messages be shown to users? -## Should diagnostics contain support procedures? +`ShortMessage`, and optionally `DetailedMessage`, are the controlled public messages: they are safe to surface to users or API clients. `DiagnosticMessage` is internal and must never be exposed. -No. Keep ticketing, escalation, and team-contact instructions outside application error documentation. Analysis leads should say where to investigate, not prescribe an organizational workflow. +“Public” means safe to expose, not necessarily final UI copy: if you need fully localized, product-styled wording, your presentation layer still owns that. The error guarantees a safe, stable message you can show or map. -See [Writing Error Documentation](WritingErrorsGuide.en.md#6-write-diagnostics-as-hypotheses). - -## Why is documentation written in code? - -Because the documentation is linked to the same factories that create the errors. It can be extracted automatically and evolves beside the behavior it describes, reducing drift. - -See [Architecture of the Documentation Pipeline](ArchitectureOfTheDocumentationPipeline.en.md). +See [Writing Error Messages](WritingErrorMessages.en.md). ## When should I add `ErrorContext`? @@ -63,41 +99,33 @@ Use it for safe, occurrence-specific facts that materially improve diagnosis or Do not use it for secrets, large payloads, generic documentation, or operational procedures. See [Error Context](ErrorContext.en.md). -## When should I use `Outcome`? - -Use it when failure is an expected branch of normal flow, such as validation, parsing, batch processing, or partial success. - -Use an exception when the failure should interrupt the operation at that level. Both paths can carry the same `Error` created by the same factory. - -See [Usage Patterns](UsagePatterns.en.md). - -## Does `Outcome` preserve a stack trace? +## Are diagnostics the same as root causes? -It does not create or throw an exception while the error is carried as data. If the failure is later escalated with `GetResultOrThrow()` or `error.ToException()`, the exception and its stack trace start at that escalation point. +No. Diagnostics are plausible hypotheses and investigation starting points. They describe what may explain the error without claiming certainty or assigning blame. -## Should I document every error? +## Should diagnostics contain support procedures? -Yes. Every error you model is meant to be documented: an undocumented error never reaches the generated catalog, and the analyzer [FCE009](analyzers/FCE009.en.md) flags any error factory you leave without documentation. +No. Keep ticketing, escalation, and team-contact instructions outside application error documentation. Analysis leads should say where to investigate, not prescribe an organizational workflow. -See [Writing Error Documentation](WritingErrorsGuide.en.md). +See [Writing Error Documentation](WritingErrorsGuide.en.md#6-write-diagnostics-as-hypotheses). -## Should every exception become a first-class error? +## Why is documentation written in code? -No. Model the meaningful application errors: recognized situations, rules, constraints, or boundary failures that benefit from a stable identity and a shared explanation. Framework exceptions, accidental crashes, and low-level implementation faults usually stay as plain technical exceptions. +Because the documentation is linked to the same factories that create the errors. It can be extracted automatically and evolves beside the behavior it describes, reducing drift. -See [When Not to Use FirstClassErrors](WhenNotToUseFirstClassErrors.en.md). +See [Architecture of the Documentation Pipeline](ArchitectureOfTheDocumentationPipeline.en.md). ## Is FirstClassErrors tied to Domain-Driven Design? No. Its vocabulary aligns well with DDD and hexagonal architecture, but any long-lived system that needs explicit error semantics, supportability, and living documentation can use it. -## Why can a domain error contain only domain errors? +## How do I nest the different error categories? A `DomainError` states that a business rule was violated. Nesting an infrastructure failure inside it would describe a technical outage as part of the domain vocabulary. A port or infrastructure error may contain a `DomainError` when a boundary-level failure is caused by a domain rejection—for example, an incoming request that cannot be mapped into a valid value object. This preserves both facts without making domain code depend on HTTP, messaging, or another adapter technology. -See the taxonomy and nesting rules in [Core Concepts](CoreConcepts.en.md#error-taxonomy). +See [Error Taxonomy and Composition](ErrorTaxonomy.en.md). --- @@ -105,4 +133,4 @@ See the taxonomy and nesting rules in [Core Concepts](CoreConcepts.en.md#error-t ← Internationalization · ↑ Table of contents ---- \ No newline at end of file +--- diff --git a/doc/FAQ.fr.md b/doc/FAQ.fr.md index 19a129b..1c5000c 100644 --- a/doc/FAQ.fr.md +++ b/doc/FAQ.fr.md @@ -7,7 +7,7 @@ C’est possible. FirstClassErrors utilise toujours les exceptions standard .NET comme mécanisme de signalement et de propagation des défaillances. -La bibliothèque enrichit l’`Error` portée par l’exception avec un code stable, du contexte structuré, des diagnostics et une documentation liée. Voir [Concepts fondamentaux](CoreConcepts.fr.md). +FirstClassErrors associe à cette exception une `Error` structurée — porteuse d’un code stable, de contexte structuré, de diagnostics et d’une documentation liée. Voir [Concepts fondamentaux](CoreConcepts.fr.md). ## Pourquoi ne pas utiliser un `Result` générique ? @@ -17,18 +17,62 @@ Vous pourriez. Transporter l’`Error` de la bibliothèque dans un type résulta Voir [Cas d’usage](UsagePatterns.fr.md) et [Comparaison avec les bibliothèques de gestion d’erreurs](ComparisonWithOtherLibraries.fr.md). +## Est-ce que FirstClassErrors remplace les logs ? + +Non. Il structure les erreurs et leur documentation ; votre système de logs enregistre leurs occurrences et leur contexte d’exécution. Une erreur de première classe donne à chaque occurrence journalisée un code stable et une explication partagée, mais elle ne stocke ni ne remplace le log lui-même. + +Voir [Intégration au logging structuré](LoggingIntegration.fr.md). + ## Est-ce trop lourd pour une application simple ? Cela peut l’être. Les petits scripts, prototypes et systèmes sans besoin durable de support peuvent être mieux servis par des exceptions standard. Voir [Quand ne pas utiliser FirstClassErrors](WhenNotToUseFirstClassErrors.fr.md) pour les critères de décision. +## Puis-je adopter FirstClassErrors progressivement ? + +Oui. Aucune migration globale n’est nécessaire. Introduisez-le là où les erreurs méritent d’être modélisées — un domaine, un module ou un use case à la fois — et laissez le reste sur des exceptions standard jusqu’à ce qu’il justifie une erreur de première classe. Comme une factory n’est qu’une façon typée de construire une `Error`, le code existant continue de fonctionner pendant que les chemins nouveaux ou repris adoptent le modèle. + +Voir [Quand ne pas utiliser FirstClassErrors](WhenNotToUseFirstClassErrors.fr.md). + +## Quand utiliser `Outcome` ? + +Utilisez-le lorsque l’échec est une branche attendue du flux normal : validation, parsing, traitement par lots ou succès partiel. + +Utilisez une exception lorsque l’échec doit interrompre l’opération à ce niveau. Les deux chemins peuvent porter la même `Error`, créée par la même factory. + +Voir [Cas d’usage](UsagePatterns.fr.md). + +## `Outcome` conserve-t-il une stack trace ? + +Aucune exception n’est créée ou levée tant que l’erreur est transportée comme donnée. Si l’échec est ensuite escaladé avec `GetResultOrThrow()` ou `error.ToException()`, l’exception et sa stack trace commencent à ce point d’escalade. + +## Toute exception doit-elle devenir une erreur de première classe ? + +Non. Modélisez les erreurs applicatives porteuses de sens : situations reconnues, règles, contraintes ou échecs de frontière qui bénéficient d’une identité stable et d’une explication partagée. Les exceptions du framework, crashes accidentels et fautes d’implémentation bas niveau restent généralement de simples exceptions techniques. + +Voir [Quand ne pas utiliser FirstClassErrors](WhenNotToUseFirstClassErrors.fr.md). + +## Comment gérer une exception provenant d’une bibliothèque tierce ? + +Attrapez-la à la frontière — en général un adaptateur ou un port secondaire — et décidez si elle représente une défaillance applicative stable. Si oui, modélisez-la via une factory sous la forme d’une `InfrastructureError` (ou une `SecondaryPortError` pour une dépendance sortante, une `PrimaryPortError` pour une entrante), placez le détail technique dans le `DiagnosticMessage` et ajoutez les faits sûrs via l’`ErrorContext`. + +L’erreur de première classe capture le *sens* de la défaillance ; elle ne stocke pas l’objet exception attrapé. Gardez l’exception d’origine à sa place — enregistrée par votre pipeline de logs au point de capture. Ne transformez pas chaque exception technique en erreur de première classe : seulement les défaillances de frontière qui méritent une identité stable. + +Voir [Taxonomie et composition des erreurs](ErrorTaxonomy.fr.md) et [Quand ne pas utiliser FirstClassErrors](WhenNotToUseFirstClassErrors.fr.md). + ## Pourquoi utiliser des factories plutôt que `new` ? -Une factory donne un nom à une situation d’erreur, centralise son code et ses messages, garde la construction hors du happy path et sert de point d’ancrage à la documentation vivante. +Une factory donne un nom à une situation d’erreur, centralise son code et ses messages, et sert de point d’ancrage à la documentation vivante. Par rapport à un `new DomainError(...)` sur chaque site d’appel, elle évite de répéter les codes, les messages et les métadonnées entre les use cases, et garde la construction de l’erreur hors du happy path. Voir [Premiers pas](GettingStarted.fr.md). +## Dois-je documenter toutes les erreurs de première classe ? + +Oui — toute erreur de première classe que vous définissez est destinée à être documentée. Une erreur non documentée n’apparaît jamais dans le catalogue généré, et l’analyseur [FCE009](analyzers/FCE009.fr.md) signale toute factory d’erreur laissée sans documentation. + +Voir [Écrire la documentation d’une erreur](WritingErrorsGuide.fr.md). + ## Quelle différence entre la documentation d’erreur et les messages runtime ? La documentation est la partie d’une erreur qui ne dépend d’aucune occurrence particulière : elle est identique pour chaque instance et ne change jamais à l’exécution. Elle sert à *comprendre* l’erreur — titre, sens, règle, hypothèses de diagnostic et exemples représentatifs. @@ -41,21 +85,13 @@ Les messages runtime sont portés par l’instance d’erreur elle-même et serv Voir [Écrire la documentation d’une erreur](WritingErrorsGuide.fr.md) et [Écrire les messages d’une erreur](WritingErrorMessages.fr.md). -## Les diagnostics sont-ils des causes racines ? - -Non. Ce sont des hypothèses plausibles et des points de départ pour l’investigation. Ils décrivent ce qui peut expliquer l’erreur sans prétendre à la certitude ni attribuer une faute. +## Les messages d’erreur peuvent-ils être affichés aux utilisateurs ? -## Les diagnostics doivent-ils contenir les procédures du support ? +`ShortMessage`, et éventuellement `DetailedMessage`, sont les messages publics maîtrisés : ils peuvent être exposés sans risque aux utilisateurs ou aux clients d’API. `DiagnosticMessage` est interne et ne doit jamais être exposé. -Non. Gardez le ticketing, l’escalade et les consignes de contact d’équipe hors de la documentation applicative. Une piste d’analyse indique où chercher ; elle ne prescrit pas un workflow organisationnel. +« Public » signifie « sûr à exposer », pas nécessairement la formulation finale de l’interface : si vous avez besoin d’un texte entièrement localisé et aux couleurs du produit, votre couche de présentation en reste responsable. L’erreur garantit un message sûr et stable que vous pouvez afficher ou mapper. -Voir [Écrire la documentation d’une erreur](WritingErrorsGuide.fr.md#6-écrire-les-diagnostics-comme-des-hypothèses). - -## Pourquoi écrire la documentation dans le code ? - -Parce qu’elle est liée aux mêmes factories qui créent les erreurs. Elle peut être extraite automatiquement et évolue à côté du comportement qu’elle décrit, ce qui réduit la dérive. - -Voir [Architecture du pipeline de documentation](ArchitectureOfTheDocumentationPipeline.fr.md). +Voir [Écrire les messages d’une erreur](WritingErrorMessages.fr.md). ## Quand ajouter un `ErrorContext` ? @@ -63,41 +99,33 @@ Utilisez-le pour des faits sûrs, propres à une occurrence, qui améliorent ré N’y placez ni secret, ni payload volumineux, ni documentation générique, ni procédure opérationnelle. Voir [Contexte d’erreur](ErrorContext.fr.md). -## Quand utiliser `Outcome` ? - -Utilisez-le lorsque l’échec est une branche attendue du flux normal : validation, parsing, traitement par lots ou succès partiel. - -Utilisez une exception lorsque l’échec doit interrompre l’opération à ce niveau. Les deux chemins peuvent porter la même `Error`, créée par la même factory. - -Voir [Cas d’usage](UsagePatterns.fr.md). - -## `Outcome` conserve-t-il une stack trace ? +## Les diagnostics sont-ils des causes racines ? -Aucune exception n’est créée ou levée tant que l’erreur est transportée comme donnée. Si l’échec est ensuite escaladé avec `GetResultOrThrow()` ou `error.ToException()`, l’exception et sa stack trace commencent à ce point d’escalade. +Non. Ce sont des hypothèses plausibles et des points de départ pour l’investigation. Ils décrivent ce qui peut expliquer l’erreur sans prétendre à la certitude ni attribuer une faute. -## Dois-je documenter toutes les erreurs ? +## Les diagnostics doivent-ils contenir les procédures du support ? -Oui. Toute erreur que vous modélisez est destinée à être documentée : une erreur non documentée n’apparaît jamais dans le catalogue généré, et l’analyseur [FCE009](analyzers/FCE009.fr.md) signale toute factory d’erreur laissée sans documentation. +Non. Gardez le ticketing, l’escalade et les consignes de contact d’équipe hors de la documentation applicative. Une piste d’analyse indique où chercher ; elle ne prescrit pas un workflow organisationnel. -Voir [Écrire la documentation d’une erreur](WritingErrorsGuide.fr.md). +Voir [Écrire la documentation d’une erreur](WritingErrorsGuide.fr.md#6-écrire-les-diagnostics-comme-des-hypothèses). -## Toute exception doit-elle devenir une erreur de première classe ? +## Pourquoi écrire la documentation dans le code ? -Non. Modélisez les erreurs applicatives porteuses de sens : situations reconnues, règles, contraintes ou échecs de frontière qui bénéficient d’une identité stable et d’une explication partagée. Les exceptions du framework, crashes accidentels et fautes d’implémentation bas niveau restent généralement de simples exceptions techniques. +Parce qu’elle est liée aux mêmes factories qui créent les erreurs. Elle peut être extraite automatiquement et évolue à côté du comportement qu’elle décrit, ce qui réduit la dérive. -Voir [Quand ne pas utiliser FirstClassErrors](WhenNotToUseFirstClassErrors.fr.md). +Voir [Architecture du pipeline de documentation](ArchitectureOfTheDocumentationPipeline.fr.md). ## FirstClassErrors est-il lié au Domain-Driven Design ? Non. Son vocabulaire s’accorde bien avec le DDD et l’architecture hexagonale, mais tout système durable qui a besoin d’une sémantique d’erreur explicite, de supportabilité et de documentation vivante peut l’utiliser. -## Pourquoi une erreur de domaine ne contient-elle que des erreurs de domaine ? +## Comment imbriquer les différentes catégories d’erreurs ? Une `DomainError` affirme qu’une règle métier a été violée. Imbriquer une défaillance d’infrastructure à l’intérieur décrirait une panne technique comme une partie du vocabulaire métier. Une erreur de port ou d’infrastructure peut contenir une `DomainError` lorsqu’un échec à la frontière est causé par un rejet métier, par exemple une requête entrante impossible à convertir en value object valide. Les deux faits sont ainsi conservés sans rendre le domaine dépendant de HTTP, de la messagerie ou d’une technologie d’adapter. -Voir la taxonomie et les règles d’imbrication dans [Concepts fondamentaux](CoreConcepts.fr.md#-taxonomie-des-erreurs). +Voir [Taxonomie et composition des erreurs](ErrorTaxonomy.fr.md). --- @@ -105,4 +133,4 @@ Voir la taxonomie et les règles d’imbrication dans [Concepts fondamentaux](Co ← Internationalisation · ↑ Table des matières ---- \ No newline at end of file +---