Compatibilité directe
Qu'est-ce que la compatibilité directe
L'interopérabilité directe est la capacité du système à travailler correctement avec des clients ou des données plus récents que ceux qu'il a initialement conçus. Plus simple : l'ancien serveur ne se casse pas quand un nouveau client lui arrive ; le vieux consommateur ne tombe pas quand il rencontre un nouveau message.
De la rétrocompatibilité (lorsque le nouveau système prend en charge les anciens clients), forward se distingue par un sens de la responsabilité : nous concevons les protocoles et les clients de manière à « survivre » aux futures extensions sans une mise à niveau totale de l'ensemble de l'écosystème.
Principes de base
1. Tolerant reader & tolerant writer
Reader ignore les champs/en-têtes inconnus et autorise de nouvelles valeurs enum avec une chute correcte.
Writer n'envoie rien que le serveur n'a pas explicitement déclaré être pris en charge (capabilities).
2. Capability negotiation
Échange explicite de possibilités (fiches/versions/types de médias) dans la phase handshake. Le client adapte son comportement à la réponse du serveur.
3. Dégradation par défaut
Les nouvelles fonctionnalités sont considérées comme facultatives : si le serveur/consumer ne les supporte pas, le script se terminera toujours par un minimum utile (MGC).
4. Noyau stable (MGC)
Le contrat minimum de garantie est inchangé ; les innovations vivent comme des extensions.
5. Les contrats d'erreur dans le cadre du protocole
Les codes/causes prévisibles (« ficha non pris en charge », « media type inconnu ») permettent au client de revenir automatiquement au mode pris en charge.
6. Versions sans surprises
Les lignes majeures sont séparées ; les extensions mineures ne nécessitent pas de mise à jour du serveur/consumer.
Où c'est particulièrement important
API publiques avec intégrations à longue durée de vie (partenaires, SDK dans les applications mobiles).
Plates-formes d'événements avec de nombreux consumers indépendants.
Clients mobiles qui se mettent à jour plus lentement que le backend.
Edge/IoT, où une partie du parc d'appareils est rarement fouillée.
Modèles d'implémentation par style
REST/HTTP
Negotiation:- 'Accept '/médiatipes avec paramètres ('application/vnd. example. order+json; v=1; profile=risk`).
- 'Prefer : include =...' pour les blocs optionnels.
- Titre "X-Capabilities : risk_score,item_details_v2'.
- Envoie la requête dans le format de base, extensions - seulement si le serveur a confirmé capability (via OPTIONS/desc/lead-endpoint).
- Dans '415/406/501', le format/méthode pris en charge est automatiquement rétrogradé.
- Réponse du serveur : paramètres inconnus - ignorer ; les champs supplémentaires sont autorisés ; le format d'erreur ('type/code/detail/trace _ id') est stable.
gRPC / Protobuf
Services stables : nouvelles méthodes/champs - additif ; l'ancien serveur ignore calmement les champs de requête inconnus.
Feature discovery : la méthode 'GetCapabilities ()' renvoie les listes fich/limites. Le client n'appelle pas la « méthode v2 » si le serveur ne l'a pas déclarée.
Streaming : enregistrer l'ordre de l'ensemble minimal de messages ; marquez les nouveaux « cadres » avec des extensions/types que l'ancien client ignore.
GraphQL
Forward-friendly : de nouveaux champs/types apparaissent sur le serveur - les anciens clients ne les demandent tout simplement pas.
Les suppositions sont interdites : le client doit garder le schéma (introspection/codogène) et ne pas envoyer de directives/variables inconnues.
Dégradation : si le serveur ne connaît pas la directive/fonctionnalité personnalisée, le client construit une requête sans elle.
Event-driven (Kafka/NATS/Pulsar, Avro/JSON/Proto)
Compatibilité FORWARD du schéma dans le registre : les anciens consumers peuvent lire les messages enregistrés par le nouveau schéma.
Champs additifs avec défauts : les nouveaux producteurs ne cassent pas les anciens consumers.
Core vs Enriched : le noyau reste le même, de nouvelles informations sont publiées dans '.enriched'ou comme champs optionnels.
Pratiques de conception
1. Contrat de demande minimale (MGC)
L'opération doit avoir un « col étroit » qui sera pris en charge par tous les serveurs pendant de nombreuses années.
2. Ficha drapeaux au niveau du contrat
Décrivez les fiches comme des fonctionnalités nommées : 'risk _ score', 'pricing _ v2', 'strong _ idempotency'. Le client les inclut explicitement.
3. Codes d'erreur explicites pour « non pris en charge »
HTTP: `501 Not Implemented`, `415 Unsupported Media Type`, детальные `problem+json`.
gRPC: `UNIMPLEMENTED`/`FAILED_PRECONDITION`.
Events : itinéraire en DLQ avec 'reason = unsupported _ feature'.
4. Ne pas compter sur l'ordre/les listes complètes
Le client doit être prêt pour les nouvelles valeurs enum, l'absence de nouveaux champs et les propriétés « supplémentaires ».
5. Identifiants et formats stables
Ne changez pas le format ID/clés de lot dans la ligne - cela brise le forward du côté des lecteurs.
6. Documentation « lisible par machine »
Hébergez les descripteurs : OpenAPI/AsyncAPI/Proto descriptors/GraphQL SDL. Les clients peuvent vérifier le support fich.
Tests de compatibilité forward
Schema-diff en mode FORWARD/FULL : le nouveau schéma valide l'ancien consommateur/serveur.
Tests contractuels du client : le nouveau client est exécuté contre l'ancien serveur avec les fiches activées/désactivées.
Golden Requests : un ensemble de « nouvelles » requêtes est lancé sur un « ancien » serveur ; on s'attend à une dégradation sans erreurs critiques.
Chaos/latency : vérification des délais/retraits - le nouveau client doit survivre correctement aux pires SLA de l'ancien serveur.
Canary : une partie des nouveaux clients fonctionne avec la version serveur précédente - nous collectons la télémétrie des erreurs/dégradations.
Observabilité et métriques opérationnelles
Proportion de requêtes/messages avec des fiches non prises en charge et leurs retours automatiques.
Distribution par version client (User-Agent/métadonnées/clims).
Erreurs 'UNIMPLEMENTED/501/415' et itinéraires dans DLQ avec 'unsupported _ feature'.
Temps de dégradation : p95/p99 pour MGC vs réponse « prolongée ».
Modes de compatibilité dans le registre des schémas
FORWARD : la nouvelle entrée est compatible avec l'ancien lecteur (il faut des défauts, une option).
FULL: и FORWARD, и BACKWARD; commode pour les marchés publics.
Recommandation : pour les événements - BACKWARD au producteur et FORWARD au consumer (via tolérant reader), pour les API externes - FULL.
Exemples
REST (capabilities + dégradation)
1. Le client fait 'GET/meta/capabilities' → {'risk_score" : false,' price_v2" : true} '.
2. Dans 'POST/orders'envoie les champs de base ; 'risk _ score' ne demande pas parce que le serveur ne le sait pas.
3. Si vous envoyez accidentellement 'Prefer : include = risk _ score', le serveur répond 200 sans le champ 'risk _ score' (ou 'Preference-Applied : none') - le client ne tombe pas.
gRPC (discovery)
« GetCapabilities () » a renvoyé la liste des méthodes/fiches. Le client n'appelle pas CaptureV2 s'il n'y en a pas - utilise plutôt Capture et convertit localement les données d'entrée jusqu'à la vue prise en charge.
Événements (FORWARD dans le registre)
Le producteur a ajouté le champ 'risk _ score' (nullable avec défaut). L'ancien consumer l'ignore ; sa logique n'utilise que les champs stables du noyau.
Anti-modèles
Client dur : filtre la réponse sur les champs whitelist et tombe sur une propriété inconnue.
Fiches implicites : le client commence à envoyer un nouveau paramètre sans vérifier les capabilities.
Le changement des formats ID/clés dans la ligne → les anciens serveurs/consumers ne comprennent plus les nouvelles requêtes/messages.
Hypothèses cousues sur la liste complète d'enum (switch sans défaut).
Loger comme contrôle de flux : parsing des lignes d'erreur au lieu des codes contractuels.
Chèque d'implémentation
- Défini par le CGM ; les nouvelles possibilités sont marquées comme facultatives.
- La negotiation capability (endpoint/métadonnées/handshake) est décrite et mise en oeuvre.
- Les clients ignorent les champs inconnus et gèrent correctement les nouveaux enum (fallback).
- Les contrats d'erreur fixent « non pris en charge » de manière prévisible (HTTP/gRPC/Event).
- Le registre des schémas est configuré sur FORWARD/FULL pour les artefacts correspondants.
- Tests automatiques : schema-diff (FORWARD), tests contractuels du client contre l'ancien serveur, canary.
- Métriques : version du client, fiche de refus, proportion de dégradations, p95 MGC.
- Les documents/SDK publient une liste de fiches et d'exemples de dégradation.
FAQ
En quoi le forward diffère-t-il du backward dans la pratique ?
Backward : le nouveau serveur ne casse pas les anciens clients. Forward : l'ancien serveur ne se casse pas des nouveaux clients (ou l'ancien consumer ne se casse pas des nouveaux messages). Idéalement, vous atteignez le plein.
Dois-je toujours introduire des capabilities ?
Si vous vous attendez à une évolution active sans versions synchrones, oui. C'est moins cher que de garder des dizaines de lignes majeures.
Qu'en est-il de la sécurité ?
Les nouvelles fiches doivent exiger des scopes/clims distincts. Si le serveur ne les prend pas en charge, le client ne doit pas réduire la sécurité, mais refuser les fiches.
Puis-je « deviner » le support selon la version du serveur ?
Pas souhaitable. Mieux vaut demander explicitement (capabilities) ou regarder la médiatip/scheme.
Résultat
L'interopérabilité directe est une discipline pour négocier les possibilités et se dégrader en toute sécurité. Un noyau stable, une negotiation capability, des extensions additives et des erreurs prévisibles permettent aux nouveaux clients et aux nouvelles données de s'entendre avec les anciens serveurs et consommateurs, sans sortie massive ni migration nocturne.