Make illegal states unrepresentable
Cette phrase, popularisée par Yaron Minsky dans le contexte d’OCaml capture l’essence même d’une approche défensive de la modélisation : plutôt que de vérifier a posteriori qu’un état est valide, on structure les types de telle sorte que les états invalides ne puissent tout simplement pas être construits. C’est un renversement de perspective fondamental : on passe d’une validation runtime à une garantie compile-time, déplaçant ainsi la détection des erreurs le plus tôt possible dans le cycle de développement.
En pratique: l’application en TypeScript
En TypeScript par exemple, cette philosophie se traduit par l’utilisation judicieuse des union types discriminées, des types littéraux et des branded types.
Prenons l’exemple classique d’une commande e-commerce :
- plutôt que d’avoir un objet avec des champs
shippedAtetdeliveredAtpotentiellement incohérents, telle qu’ne commande livrée mais jamais expédiée… - on modélise explicitement les états
Draft | Confirmed | Shipped | Deliveredcomme des variantes distinctes, chacune ne portant que les données pertinentes à son état.
Le compilateur devient alors un gardien qui refuse de compiler du code tentant de créer des combinaisons impossibles du point de vue métier.
Alignement avec le Domain-Driven Design
Du point de vue du Domain-Driven Design, cette approche s’aligne parfaitement avec la notion d’invariants d’agrégat. Un agrégat bien conçu ne devrait jamais pouvoir être instancié dans un état qui viole ses règles métier. Les Value Objects incarnent particulièrement bien ce principe : un EmailAddress n’est pas une simple string, c’est un type qui, par construction, garantit la validité de son contenu.
On élimine ainsi toute une classe de bugs liés à la propagation de données invalides à travers le système.
En contexte réglementaire, cette approche simplifie aussi les audits. Quand un auditeur demande « votre système peut-il se retrouver dans l’état X ? », si le système de types rend X inexprimable, la réponse est une preuve formelle, pas une promesse basée sur des tests ou des revues de code.
Réduction du gaspillage au sens Lean
Cette technique constitue également un levier puissant pour réduire le muda (gaspillage) au sens Lean. Chaque état impossible que vous rendez inexprimable, c’est : un bug qui n’existera jamais, un test que vous n’avez pas besoin d’écrire, un ticket support qui ne sera jamais ouvert. Chaque validation manuelle qu’on n’a plus besoin d’écrire, chaque bug en production qu’on n’aura jamais à investiguer représente du temps et de l’énergie économisés.
Le système de types devient une forme de documentation exécutable et vérifiée automatiquement, réduisant la charge cognitive des développeurs qui n’ont plus à garder en tête tous les états théoriquement possibles mais, en pratique, interdits par le métier.
Limites et compromis
Il faut cependant reconnaître les limites de cette approche:
- Certains invariants sont intrinsèquement dynamiques : l’unicité d’un email dans une base de données, par exemple, ne peut pas être encodée dans le système de types seul.
- De plus, une modélisation trop fine peut engendrer une explosion combinatoire de types qui nuit à la lisibilité.
L’art réside dans le discernement : identifier les invariants critiques qui méritent d’être encodés statiquement, tout en acceptant que certaines validations resteront nécessairement au runtime. C’est un compromis pragmatique entre sécurité et ergonomie.
Envie d'approfondir ces sujets ?
Nous aidons les équipes à adopter ces pratiques via du conseil et de la formation.
ou écrivez-nous à contact@evryg.com