Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion doc/handwritten/for-maintainers/README.fr.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

> Documentation pour les **mainteneurs et opérateurs** de FirstClassErrors —
> comment le projet est construit, publié et maintenu en bonne santé. Elle ne
> fait **pas** partie de la documentation utilisateur de la librairie, sous
> fait **pas** partie de la documentation utilisateur de la bibliothèque, sous
> [`doc/`](../for-users/). La version anglaise est canonique ; les pages françaises sont
> tenues à jour en parallèle.

Expand Down
2 changes: 1 addition & 1 deletion doc/handwritten/for-maintainers/ReleaseDryRun.fr.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ référence des workflows pour [`release`](workflows/release.fr.md) et
[`release-dryrun`](workflows/release-dryrun.fr.md).

> Documentation technique / mainteneur. Elle ne fait **pas** partie de la
> documentation utilisateur de la librairie, sous `doc/`.
> documentation utilisateur de la bibliothèque, sous `doc/`.

## De quoi s'agit-il

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ une brèche que les autres ne peuvent fermer :
de l'assembly et échoue, rapidement et in-process, si un quelconque assembly
`Microsoft.CodeAnalysis*` référencé le dépasse — attrapant la dérive de
*référence* ;
* **le job CI de floor-check** empaquette la librairie et reconstruit
* **le job CI de floor-check** empaquette la bibliothèque et reconstruit
l'exemple contre l'analyzer empaqueté sous le SDK du floor, prouvant que
l'**artefact livré** à la fois se **charge** et est **packagé** correctement sur
le **compilateur pris en charge le plus ancien** — les deux brèches que le test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@

FirstClassErrors livre deux types d'artefacts très différents :

* la **librairie** (`FirstClassErrors`, `FirstClassErrors.Testing`) cible
**`netstandard2.0`**. Une librairie netstandard est consommée par
* la **bibliothèque** (`FirstClassErrors`, `FirstClassErrors.Testing`) cible
**`netstandard2.0`**. Une bibliothèque netstandard est consommée par
*n'importe quel* runtime qui implémente le standard — .NET Framework 4.6.1+,
.NET Core 2.0+, .NET 5–10+, Mono/Unity — de sorte que la question
« fonctionne presque partout » est déjà résolue, une seule fois, par le TFM,
Expand All @@ -26,9 +26,9 @@ FirstClassErrors livre deux types d'artefacts très différents :

Le TFM de l'outillage décide donc *quels consommateurs peuvent exécuter `fce`
tout court*. Il était à `net10.0`, ce qui signifiait qu'un atelier dont le
runtime installé le plus récent est .NET 8 pouvait référencer la librairie
runtime installé le plus récent est .NET 8 pouvait référencer la bibliothèque
mais **ne pouvait pas exécuter le générateur de documentation** — alors même que
la librairie qu'il documente est `netstandard2.0`.
la bibliothèque qu'il documente est `netstandard2.0`.

Il existe une seconde contrainte, plus subtile. Le worker charge l'assembly
**cible** via `Assembly.LoadFrom` (voir
Expand Down Expand Up @@ -61,7 +61,7 @@ avec le roll-forward, et non une matrice de cibles.
## Justification

Le floor réduit l'histoire du support à une seule phrase : *FirstClassErrors
supporte .NET 8 et au-delà pour son outillage et son analyzer ; la librairie
supporte .NET 8 et au-delà pour son outillage et son analyzer ; la bibliothèque
elle-même est `netstandard2.0` et descend jusqu'à .NET Framework 4.6.1.* Le
floor de l'outillage et le floor de l'analyzer (ADR-0001) énoncent le **même**
minimum, de sorte que le produit énonce **un seul** chiffre de support.
Expand All @@ -72,7 +72,7 @@ Le roll-forward couvre tous les runtimes plus récents, ajusté par processus :
|---|---|---|
| `FirstClassErrors.Cli` (`fce`) | `Major` | Le front-end a seulement besoin de *s'exécuter*. `Major` monte le build net8 à la majeure suivante lorsque .NET 8 est absent, de sorte qu'une machine qui n'a que .NET 10 l'exécute (monte 8→10). Sans lui, la politique `Minor` par défaut ne franchit jamais une majeure et `fce` échouerait à démarrer sur la machine courante « .NET plus récent, pas de .NET 8 ». |
| `FirstClassErrors.GenDoc.Worker` | `LatestMajor` | Le worker doit **surclasser la cible qu'il charge**. `Major` ne monte que lorsque la majeure demandée est *absente*, de sorte que sur une machine qui embarque **à la fois** .NET 8 et .NET 10, un worker net8 se lierait à 8 et échouerait à charger une cible net10. `LatestMajor` se lie toujours à la **plus haute** majeure **installée**, de sorte que le worker peut documenter une cible compilée pour n'importe quel runtime présent. |
| `FirstClassErrors.GenDoc` | — | Chargé in-process par `fce` ; le runtime est choisi par le runtimeconfig de la CLI, de sorte qu'une librairie ne fixe aucune politique. |
| `FirstClassErrors.GenDoc` | — | Chargé in-process par `fce` ; le runtime est choisi par le runtimeconfig de la CLI, de sorte qu'une bibliothèque ne fixe aucune politique. |

`<LangVersion>latest</LangVersion>` reste sur les trois projets afin que le floor
net8 ne borne que la **surface BCL et le runtime cible**, et non le C# que la
Expand Down Expand Up @@ -121,7 +121,7 @@ roll-forward.

Rejeté parce que le TFM est un minimum strict pour une application dépendante du
framework : un atelier dont le runtime installé le plus récent est .NET 8
pourrait référencer la librairie `netstandard2.0` mais ne pourrait pas
pourrait référencer la bibliothèque `netstandard2.0` mais ne pourrait pas
exécuter le générateur de documentation qui la documente.

### Multi-cibler l'outillage (`net8.0;net10.0`)
Expand Down Expand Up @@ -168,7 +168,7 @@ simple et a la même portée.
* `fce` ne peut pas s'exécuter sur une machine dont le runtime le plus récent
est antérieur à .NET 8 (par exemple un .NET 6/7 en EOL, ou uniquement
.NET Framework). Accepté : ces consommateurs **utilisent** toujours la
librairie `netstandard2.0` dans leur application ; exécuter un *outil* de
bibliothèque `netstandard2.0` dans leur application ; exécuter un *outil* de
dev/CI sur un runtime actuellement supporté est un prérequis raisonnable (un
SDK .NET moderne est déjà présent partout où l'on compile du .NET moderne).

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,12 @@

## Contexte

* `Outcome` et `Outcome<T>` sont le type de résultat succès-ou-échec de la librairie ; ils se composent au travers d'une petite surface fluide.
* `Outcome` et `Outcome<T>` sont le type de résultat succès-ou-échec de la bibliothèque ; ils se composent au travers d'une petite surface fluide.
* Deux opérations de composition existaient sous des noms distincts : `Then` enchaînait avec une fonction pouvant elle-même échouer (elle retourne un `Outcome`), et `To` transformait une valeur en cas de succès avec une fonction ne pouvant pas échouer (elle retourne une valeur simple). Ce sont les opérations *bind* et *map* de la programmation fonctionnelle.
* L'objectif affiché de la librairie est une API nommée pour l'**intention**, non pour la mécanique de la programmation fonctionnelle ; la FAQ défend ce choix précis lorsqu'elle oppose `Outcome` à un `Result<T, Error>` générique.
* L'objectif affiché de la bibliothèque est une API nommée pour l'**intention**, non pour la mécanique de la programmation fonctionnelle ; la FAQ défend ce choix précis lorsqu'elle oppose `Outcome` à un `Result<T, Error>` générique.
* Le fait qu'une étape de composition puisse échouer est déjà exprimé par le type de retour de la fonction que l'appelant fournit : une fonction retournant un `Outcome` peut échouer ; une fonction retournant une valeur ne le peut pas.
* C# interdit la surcharge sur le seul type de retour, et sa résolution de surcharge sélectionne le type de paramètre le plus spécifique lorsque plusieurs candidats s'appliquent. La distinction map/bind est donc imposée par le système de types à chaque site d'appel, indépendamment du nom de la méthode.
* La librairie est en pré-version : non publiée sur NuGet, sans consommateurs externes, de sorte qu'un renommage cassant n'entraîne aujourd'hui aucun coût de migration en aval.
* La bibliothèque est en pré-version : non publiée sur NuGet, sans consommateurs externes, de sorte qu'un renommage cassant n'entraîne aujourd'hui aucun coût de migration en aval.

## Décision

Expand All @@ -32,7 +32,7 @@ L'opération de transformation de valeur sur `Outcome` est exposée sous forme d

Envisagée parce qu'elle reflète la nomenclature établie `map`/`bind` familière aux praticiens de la programmation fonctionnelle et garde chaque opération sans ambiguïté par elle-même.

Rejetée parce qu'elle expose précisément la mécanique que la librairie masque délibérément, et la distinction échec/sans-échec qu'elle encode est déjà portée par le type de retour de la fonction fournie — le second nom ajoute du vocabulaire sans ajouter d'information.
Rejetée parce qu'elle expose précisément la mécanique que la bibliothèque masque délibérément, et la distinction échec/sans-échec qu'elle encode est déjà portée par le type de retour de la fonction fournie — le second nom ajoute du vocabulaire sans ajouter d'information.

### Conserver `To` comme alias déprécié de `Then`

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ une erreur est une valeur qu'un appelant retourne et inspecte
La levée d'exception reste prise en charge comme commodité optionnelle — le README
la présente comme un choix (« vous choisissez comment elle circule ») — mais
retourner un `Outcome` est le chemin par défaut et de première classe de la
librairie.
bibliothèque.

Les opérations de type fabrique se présentent donc couramment en deux variantes
sur les mêmes entrées : l'une retourne `Outcome<T>`, l'autre lève une exception en
Expand All @@ -30,18 +30,18 @@ fournit sa valeur via un paramètre `out`, et se lit en ligne dans un `if`
présument tous cette forme exacte à la vue d'un préfixe `Try`. Deux faits en
découlent :

* **Forme.** Un `TryXxx` dans cette librairie retourne `Outcome<T>` — il
* **Forme.** Un `TryXxx` dans cette bibliothèque retourne `Outcome<T>` — il
emprunte le nom sans la forme `bool`+`out`, si bien qu'il ne peut pas être
utilisé en ligne dans un `if` et rompt discrètement l'attente que le nom
établit.
* **Disposition.** Dans la BCL, le nom *simple* est celui qui lève (`Parse`) et le
nom *marqué* est celui qui est sûr (`TryParse`). Le code actuel suit cette
disposition (`FromKelvin` lève, `TryFromKelvin` est sûr) — plaçant le nom
simple, non marqué, sur le chemin qui lève, c'est-à-dire le chemin que cette
librairie traite comme l'exception plutôt que comme le défaut.
bibliothèque traite comme l'exception plutôt que comme le défaut.

`Outcome<T>` expose déjà `GetResultOrThrow()`, si bien que « lever en cas
d'échec » dispose d'un vocabulaire établi dans la librairie.
d'échec » dispose d'un vocabulaire établi dans la bibliothèque.

## Décision

Expand All @@ -51,15 +51,15 @@ retournant `Outcome<T>`) ; la variante qui lève est marquée d'un suffixe `OrTh

## Justification

* **Un seul principe, appliqué au défaut de cette librairie.** La convention qui
* **Un seul principe, appliqué au défaut de cette bibliothèque.** La convention qui
mérite d'être conservée de la BCL n'est pas le mot `Try` mais la règle
sous-jacente : *la variante qui s'écarte du défaut dominant porte le marqueur.*
Le défaut de la BCL est de lever, donc sa variante sûre est marquée (`Try`) ; le
défaut de cette librairie est de retourner un `Outcome`, donc sa variante qui
défaut de cette bibliothèque est de retourner un `Outcome`, donc sa variante qui
lève est l'écart et prend le marqueur (`OrThrow`). Même règle, référence opposée
— ce qui est précisément la raison pour laquelle réutiliser `Try` ici serait
incohérent, et non un simple conflit de noms.
* **L'appel risqué est celui qui est visible.** Toute la thèse de la librairie
* **L'appel risqué est celui qui est visible.** Toute la thèse de la bibliothèque
est qu'une exception est le mode d'échec qui se cache au site d'appel. `OrThrow`
la remet dans le nom : `FromKelvinOrThrow(k)` annonce qu'elle peut lever ;
`FromKelvin(k)` annonce qu'elle retourne une valeur à inspecter. Le nom simple et
Expand All @@ -82,7 +82,7 @@ C'est la disposition de la BCL : le nom simple lève, le nom marqué retourne un
`XxxOrError`, `AttemptXxx`, `XxxSafe` — la disposition partage un même défaut :
elle laisse l'appel qui *lève* non marqué, de sorte que le seul appel qui peut
échouer de manière invisible porte le nom le plus court et le plus semblable à un
défaut. Pour une librairie dont la raison d'être est de rendre explicite le
défaut. Pour une bibliothèque dont la raison d'être est de rendre explicite le
chemin d'échec, c'est à l'envers. `Try` entre de plus en conflit avec la forme de
la BCL ; les autres évitent le conflit mais pas le défaut sous-jacent.

Expand All @@ -100,7 +100,7 @@ introduire un synonyme fragmenterait le vocabulaire.
d'appel : un `FromKelvin` simple retourne un `Outcome` à inspecter, tandis que
`FromKelvinOrThrow` annonce d'emblée qu'il peut lever.
* Le nom simple, celui vers lequel on se tourne le plus, appartient désormais au
chemin de première classe de la librairie, si bien que la variante vers
chemin de première classe de la bibliothèque, si bien que la variante vers
laquelle un appelant se dirige par défaut est celle qui est inspectable.
* Aucune méthode n'annonce la forme `Try`/`out` de la BCL qu'elle n'implémente pas.

Expand All @@ -115,7 +115,7 @@ introduire un synonyme fragmenterait le vocabulaire.
* Les exemples de documentation qui utilisent le préfixe `Try` (`GettingStarted`,
`UsagePatterns`, en EN comme en FR) doivent être reformulés avec les nouveaux
noms.
* Il s'agit d'un renommage cassant de membres publics. La librairie est en
* Il s'agit d'un renommage cassant de membres publics. La bibliothèque est en
pré-version et non publiée sur NuGet, sans consommateurs externes, si bien
qu'elle n'entraîne aujourd'hui aucun coût de migration en aval.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ manière dont ces entrées sont fournies aujourd'hui.
à cette unique constante). Une valeur qui varie d'une exécution à l'autre fait
apparaître un tel couplage.

Les librairies établies résolvent cela avec un dispositif de « valeur
Les bibliothèques établies résolvent cela avec un dispositif de « valeur
anonyme / arbitraire » (AutoFixture, Bogus, l'utilitaire `Any` de GOOS, les
générateurs FsCheck). En adopter un ici doit satisfaire deux contraintes
strictes de ce package :
Expand Down Expand Up @@ -120,7 +120,7 @@ avant.
### Ajouter des fabriques de test aux value objects eux-mêmes

Placer « fabrique-en une arbitraire » sur `ErrorCode`, `Error`, et consorts dans
la librairie cœur. Rejeté parce que cela mêle une préoccupation de test à des
la bibliothèque cœur. Rejeté parce que cela mêle une préoccupation de test à des
types de production et livrerait une surface réservée aux tests dans le package
principal.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,14 +28,14 @@
consommateur dont la fabrique retourne `Outcome<TCommand>` à imbriquer le résultat sous
la forme `Outcome<Outcome<TCommand>>`, et ne laisse aucun endroit où exécuter une règle
inter-champs.
* La librairie réserve déjà le nom de fabrique simple à la variante retournant un
* La bibliothèque réserve déjà le nom de fabrique simple à la variante retournant un
`Outcome` (ADR-0005) ; dans tout le code, les fabriques `Parse` / `Create` des value
objects retournent `Outcome<T>`, si bien que « une fabrique au nom simple restitue un
`Outcome` » constitue un vocabulaire établi.
* L'assembleur reçoit un `BindingScope`, un `readonly ref struct` ; un ref struct ne peut
pas être un argument de type générique, si bien qu'un assembleur ne peut pas être un
`Func<>` et doit être un type delegate nommé.
* La librairie est en pré-version, non publiée sur NuGet et sans consommateurs
* La bibliothèque est en pré-version, non publiée sur NuGet et sans consommateurs
externes, si bien qu'un choix de nommage sur cette nouvelle API n'entraîne aucun coût
de migration en aval.

Expand Down
Loading