12. Les contrats : évoluer sans surprendre les consommateurs
Pourquoi ce chapitre existe
Une interface est une promesse faite à quelqu'un d'autre : un client web, une application mobile, une autre équipe, un partenaire ou un traitement différé. Les ruptures les plus coûteuses ne proviennent pas toujours d'une suppression spectaculaire. Un champ qui change de sens, une erreur qui devient silencieuse ou un événement émis dans un ordre différent peut casser un consommateur tout en laissant le producteur parfaitement vert.
Les contrats permettent de faire évoluer le système sans exiger une coordination totale à chaque changement. Ils doivent donc décrire non seulement la forme des messages, mais aussi le comportement sur lequel les consommateurs peuvent raisonnablement compter.
Les idées essentielles
- Un contrat comprend structure, sémantique, erreurs, temporalité et garanties opérationnelles pertinentes.
- La compatibilité dépend du point de vue : ce qui est rétrocompatible pour le producteur peut ne pas l'être pour un consommateur existant.
- Versionner n'est pas une excuse pour abandonner la compatibilité ; c'est un mécanisme de transition avec un coût de maintenance.
- Les tests de contrat vérifient un engagement ciblé. Ils ne remplacent ni les tests métier ni l'observation de production.
La forme d'un contrat ne suffit pas
Imaginons un événement CommandeExpédiée qui contient dateExpedition. Ajouter un champ dateLivraisonPrevue semble sans danger. Pourtant, si certains consommateurs interprètent l'absence comme une livraison immédiate, ou si le nouveau champ n'est calculé que pour certaines régions, le changement introduit une nouvelle sémantique qui doit être déclarée. De même, changer une valeur possible de statut peut être incompatible même si le type reste une chaîne de caractères.
Un contrat utile précise ce qui est important pour le consommateur :
| Dimension | Question à expliciter |
|---|---|
| Structure | Quels champs existent, lesquels sont requis, quelles sont leurs contraintes ? |
| Sémantique | Que signifie chaque valeur, y compris l'absence et les cas inconnus ? |
| Erreurs | Quelles erreurs sont possibles, distinguables et stables ? |
| Temps | Quel ordre, délai, niveau de fraîcheur ou répétition est possible ? |
| Évolution | Quelles additions sont tolérées, comment une dépréciation est-elle annoncée ? |
| Exploitation | Quelles limites, identifiants de corrélation ou garanties de disponibilité sont attendus ? |
Compatibilité dans les deux sens
Une modification additive est souvent compatible avec les consommateurs existants, à condition qu'ils tolèrent les champs inconnus. Elle peut ne pas être compatible avec un ancien producteur si le consommateur mis à jour exige déjà la nouvelle donnée. Les transitions sûres exigent de connaître les versions qui coexistent et le sens du déploiement.
Cette discipline est particulièrement importante pour les clients qui ne se déploient pas en même temps que le serveur : mobiles, intégrations partenaires, exports ou consommateurs de données. Une API interne peut également compter des versions anciennes si les équipes déploient à des rythmes différents.
Déprécier est une responsabilité de produit
Supprimer un élément de contrat n'est pas un nettoyage technique neutre. Il oblige des consommateurs à agir, souvent avec des priorités et des contraintes qui ne sont pas celles du producteur. Une dépréciation responsable identifie les usages, fournit une alternative, annonce un horizon réaliste, mesure la migration et communique le risque.
Lorsqu'un consommateur est inconnu, l'incertitude elle-même est un risque de contrat. Les journaux d'accès, clés de client, métriques d'usage ou un mécanisme de version explicite peuvent être nécessaires avant toute suppression. « Nous n'avons pas connaissance de client » ne signifie pas « aucun client n'existe ».
Les versions proliférantes multiplient la documentation, les chemins de support et le coût de sécurité. Préserver la compatibilité quand elle est raisonnable reste la stratégie la moins chère. Une rupture assumée se justifie lorsque l'ancien contrat ne peut pas être sécurisé, compris ou maintenu sans dommage disproportionné.
Anti-patterns
Utiliser une documentation statique comme seule source de vérité
Une page d'API peut être exacte le jour de sa publication et devenir fausse au fil des déploiements. La documentation est nécessaire, mais les contrats critiques gagnent à être vérifiés automatiquement contre les comportements réellement exposés.
Publier un événement comme s'il s'agissait d'un détail interne
Dès qu'un autre composant ou une autre équipe consomme un événement, son nom, ses champs et sa sémantique deviennent un engagement. Changer silencieusement son ordre ou son contenu est une rupture de contrat, même si le producteur compile.
Imposer au consommateur de deviner les évolutions
Le consommateur « robuste » qui ignore tout état inconnu peut éviter une panne immédiate. Il peut aussi continuer avec une décision dangereuse. Prévoir une valeur explicite, une capacité de négociation ou un échec lisible est souvent plus sûr que le silence.
Bonnes pratiques
Écrire les exemples de contrat comme des scénarios
Un exemple nominal, un exemple d'erreur, un cas de valeur inconnue et un cas de transition rendent un contrat plus compréhensible qu'une liste de champs seule. Ces exemples peuvent alimenter les tests de contrat et les environnements de simulation, à condition de représenter des comportements réellement supportés.
Planifier le cycle de vie complet
À l'ajout, décider comment le contrat sera observé et quelles compatibilités sont promises. À la dépréciation, identifier les consommateurs et le seuil de suppression. À la suppression, vérifier l'usage réel et supprimer également les métriques, documentation et chemins de compatibilité devenus inutiles.
Checklist — Un contrat peut-il évoluer en sécurité ?
- Quels consommateurs connus et potentiels dépendent de cette interface ?
- Quelles sémantiques, erreurs et propriétés temporelles peuvent-ils observer ?
- Les anciennes et nouvelles versions peuvent-elles coexister dans les deux sens de déploiement ?
- Quelle preuve automatique vérifie l'engagement le plus critique ?
- Comment l'usage de l'ancien contrat sera-t-il mesuré pendant la transition ?
- Quelle date, quel responsable et quel critère permettent de supprimer la compatibilité ?
À retenir
Un contrat n'est pas un format sérialisé. C'est une promesse de comportement entre parties qui évoluent à des rythmes différents. Le rendre explicite, vérifiable et dépréciable transforme la compatibilité d'une chance en capacité d'ingénierie.