Accueil / Articles / Évaluer la dette liée à la conception des schémas GraphQL à l’aide de LLM et d’un mécanisme d’amélioration continue

Évaluer la dette liée à la conception des schémas GraphQL à l’aide de LLM et d’un mécanisme d’amélioration continue

Comment utiliser un évaluateur d’LLM et une échelle de notation de 1 à 5 pour détecter les problèmes subjectifs dans la conception GraphQL des nouvelles demandes de fusion et identifier la dette technique déjà présente dans votre schéma.

1929 mots

Même avec un guide de style excellent, un schéma GraphQL modifié par des dizaines ou des centaines d’ingénieurs dans de nombreux domaines produits finit par s’éloigner de son objectif initial. Les outils de linting détectent les problèmes mécaniques, mais ceux qui sont plus coûteux relèvent du jugement : une variable String qui aurait dû être un enum, une liste qui continue de s’allonger indéfiniment, un champ nullable qui ne retourne jamais réellement la valeur null. Cet article décrit un système en deux parties pour gérer de tels cas : un outil d’évaluation assisté par un LLM qui empêche l’apparition de nouvelles dettes techniques dès la soumission d’une demande de modification, ainsi qu’un système de notation du schéma existant qui transforme ces anciennes dettes en une liste de tâches à traiter par ordre de priorité, contrôlée par des mécanismes CI.

Pourquoi la qualité de l’API devient un problème systémique

Avec un petit nombre d’ingénieurs, disposer d’une API cohérente relève principalement d’une question de goûts partagés. Les personnes travaillent côte à côte, examinent les modifications apportées aux schémas respectifs et aboutissent aux mêmes modèles. À mesure que l’organisation grandit, cette approche cesse de fonctionner. De nouvelles fonctionnalités sont constamment mises en production, les anciennes conventions coexistent avec de nouvelles, et les décisions qui semblaient évidentes pour l’équipe initiale sont appliquées différemment par des équipes qui ne les ont jamais rencontrées.

À ce stade, trois questions nécessitent des réponses qui ne dépendent pas de l’attention d’un seul examinateur :

  • Comment maintenir une conception d’API cohérente lorsque de nombreuses équipes modifient le schéma en parallèle ?
  • Comment s’assurer que les nouveaux types et champs respectent les meilleures pratiques actuelles ?
  • Comment identifier les parties de l’API qui ont été conçues avant l’existence de ces pratiques ?

Les deux premiers concernent la prévention. Le troisième porte sur l’archéologie, et c’est celui que la plupart des efforts de gouvernance ignorent.

Où s’arrêtent les règles de linting et où commence le jugement

Une grande partie des normes API est de nature mécanique, et l’analyse statique s’en occupe très bien. Les conventions de nommage, l’utilisation de champs obsolètes, les descriptions obligatoires et une forme d’erreur cohérente sont toutes des propriétés binaires du schéma : un champ soit respecte la règle, soit il ne la respecte pas, et un outil de linting peut indiquer lequel.

D’autres normes ne peuvent pas être réduites à une règle simple. Exemples typiques :

  • Ce String devrait-il être un enum ?
  • Cette liste devrait-elle être paginée ?
  • Ce Int devrait-il être un scalaire personnalisé ?
  • Ce champ nullable pourrait-il devenir sûrement non-null ?
  • Cette forme correspond-elle à la manière dont des concepts similaires sont modélisés ailleurs dans l’API ?

Aucune de ces questions ne possède une réponse sans contexte. Retourner une String, ou même un bloc JSON non typé, peut parfois être correct. Pour déterminer si c’est le cas, il faut examiner trois éléments ensemble : la déclaration du schéma, l’implémentation du résolveur qui la gère, ainsi que l’intention derrière la mise à disposition de ces données aux clients. Ce n’est qu’en tenant compte des trois que l’on peut juger de la forme qui conviendra le mieux aux clients.

Les organisations gèrent généralement cela par des revues de code, des séances d’entretien avec l’équipe de la plateforme, et des directives écrites. Cette approche fonctionne, mais elle a du mal à s’adapter à des projets de plus en plus importants. La pression liée aux délais raccourcit les temps de revue, l’équipe de la plateforme ne peut pas examiner chaque modification de schéma dans chaque répertoire, et les meilleures pratiques évoluent plus rapidement que les anciennes API ne sont révisées. Le résultat est deux problèmes liés : empêcher l’accumulation de dettes techniques nouvelles, et identifier celles qui existent déjà.

Se déplacer vers la gauche : un correcteur basé sur des LLM pour les modifications de schéma

La première moitié du système encode les directives de conception API en un agent d’analyse de code automatisé. L’objectif n’est pas de remplacer les évaluateurs humains, mais de leur fournir un deuxième regard sur précisément les problèmes qui échappent à une analyse normale de demande de fusion. Faire approuver personnellement par l’équipe de la plateforme chaque modification GraphQL dans tous les répertoires n’est pas scalable ; en revanche, intégrer les normes préférées dans un évaluateur IA qui fonctionne partout l’est.

Puisque l’agent voit plus que simplement les différences de schéma, il peut prendre en compte le contexte plutôt que la syntaxe. Il lit la déclaration, l’implémentation correspondante au champ ainsi que le texte de politique pertinent, avant de soulever des questions spécifiques. Deux commentaires représentatifs :

  • Un champ nommé updatedAt est déclaré comme de type String. Si le résolveur renvoie une date-timestamp ISO 8601, il devrait probablement utiliser plutôt le scalaire dédié ISO8601DateTime.
  • Company.employees renvoie une simple liste. La main-d’œuvre d’une entreprise n’a pas de limite supérieure naturelle, donc ce champ devrait renvoyer une connexion paginée.

Aucun de ces cas ne peut être détecté de manière fiable par un outil de vérification syntaxique. Une règle de ce type stipulant que "les champs se terminant par At doivent être des scalaires de date" génère des faux positifs et manque le champ lastModified ; une règle exigeant que "toutes les listes soient paginées"> est inappropriée pour un champ renvoyant les trois devises prises en charge. L’LLM peut alors examiner ce que fait réellement le résolveur.

Le facteur décisif est le timing. Détecter ces problèmes tant que l’API est encore en phase de conception est peu coûteux. Les découvrir après que les clients ont adopté sa structure implique un cycle de dépréciation et une migration.

Regarder en arrière : évaluer le schéma que vous possédez déjà

La prévention ne sert à rien pour la superficie existante, et dans une API mature, cette superficie est importante. Une partie de celle-ci remonte à avant les normes actuelles. D’autres parties reflètent des compromis qui semblaient pertinents au moment de leur adoption. Enfin, certaines parties sont simplement inégales, car des équipes distinctes ont modélisé le même concept à leur manière. Il vous faut donc un moyen de regarder en arrière.

La seconde partie du système est un processus par lots qui complète les outils d’analyse statique déjà utilisés pour parser le schéma. Son flux de travail est le suivant :

  1. Parcourir le schéma domaine par domaine et sélectionner les champs ou types pour lesquels un jugement subjectif sur la conception est nécessaire.
  • Rassembler la déclaration du schéma ainsi que le code d’implémentation correspondant.
  • Envoyer ce contexte à un LLM dans une demande qui inclut les politiques de conception API écrites.
  • Demander au modèle si ce champ semble enfreindre l’une de ces pratiques subjectives.
  • Enregistrer le résultat sous forme de score accompagné d’une explication écrite.
  • Résumer les résultats par domaine de produit ou équipe responsable.
  • La première étape est importante pour les coûts et la qualité des résultats. Il n’y a aucune raison de demander à un modèle des informations concernant des champs déjà classés par une vérification déterministe ; le LLM ne doit examiner que les cas où un jugement est réellement nécessaire.

    Pourquoi un score de 1 à 5 est préférable à un résultat réussi/échoué

    Puisqu’il s’agit de jugements subjectifs, forcer chaque résultat dans une réponse binaire entraîne la perte d’informations. Au lieu de cela, chaque champ reçoit un score d’évaluation allant de 1 à 5 :

    • 1 : le champ semble approprié tel que conçu.
    • 2 : le signal est faible, mais il devrait probablement être acceptable.
    • 3 : une personne doit y jeter un coup d’œil.
    • 4 : le champ viole probablement les règles en vigueur.
    • 5 : le champ constitue un exemple typique du schéma à éviter.

    Pour le préciser : un champ de type String contenant du texte écrit par l’utilisateur de manière arbitraire devrait se situer près de 1. Un champ de type String nommé errorCode dont le mécanisme de résolution ne peut retourner qu’une des trois valeurs prédéfinies devrait se situer près de 5, car il s’agit en réalité d’une enum déguisée.

    Un score gradué fournit un indicateur bien plus utile qu’une simple liste des violations. Les équipes peuvent commencer par les notes de haute confiance (4 et 5) tout en identifiant les zones à moindre confiance qui méritent une analyse plus approfondie. Le milieu de l’échelle a une seconde utilité : un groupe de notes 3 indique à l’équipe de la plateforme où le libellé de la politique ou la question posée est ambigu, ce qui constitue un retour d’information pour affiner les questions de jugement afin d’obtenir des résultats plus fiables.

    Si vous développez quelque chose de similaire, demandez au modèle une sortie structurée (un score et une explication dans des champs séparés) afin que les résultats puissent être stockés et agrégés sans avoir à analyser du texte narratif. Gardez également le texte de la politique et la version du critère d’évaluation en parallèle de la question posée, afin que les changements de score puissent être rattachés aux modifications des règles.

    Transformer les constats en actions

    Les scores dans une base de données ne changent pas d’eux-mêmes. En les regroupant par domaine dans un tableau de bord, chaque équipe responsable obtient une vision concrète des dettes liées à la conception de l’API dans son domaine : pas de faits isolés ou de commentaires d’évaluation ponctuels, mais une liste priorisée des champs et types qui pourraient nécessiter une migration.

    Ces mêmes données permettent d’améliorer progressivement l’intégration continue. Il ne s’agit pas de tout corriger d’un coup, ce qui est irréaliste pour une grande API ayant de nombreux clients en production. L’objectif est de s’assurer que la situation ne s’aggrave pas, tout en améliorant progressivement l’état actuel de l’API :

    • Tous les nouveaux changements de schéma doivent respecter la norme en vigueur.
    • Les problèmes existants sont enregistrés comme des dettes connues, plutôt que d’être ignorés discrètement.
    • Au fur et à mesure que les équipes migrent ou suppriment de vieux schémas, le seuil autorisé est resserré, afin que les dettes corrigées ne reviennent pas.

    Les engrenages constituent un schéma courant dans les migrations de nettoyage : on enregistre le nombre actuel de violations par domaine, on bloque la compilation si un changement l’augmente, et on abaisse le seuil enregistré chaque fois que quelqu’un corrige une instance.

    Cette approche est particulièrement importante pour les API publiques ou largement utilisées, où le nettoyage dépend des migrations des clients. Le résultat n’est pas une instruction pour supprimer chaque champ défectueux, mais plutôt une carte priorisée des endroits où l’API ne correspond plus aux normes actuelles, afin que les équipes puissent planifier leurs actions en conséquence.

    Pourquoi un LLM est l’outil idéal pour cette tâche

    Les LLM ne sont pas des juges infaillibles de la conception d’API, et le système ne les considère pas comme tels. Leur force réside plutôt dans leur capacité à lire ensemble du code et des schémas, à les comparer aux règles formulées en langage courant, et à produire une évaluation structurée pour les cas que aucune règle statique ne peut couvrir.

    Une règle statique peut indiquer qu’un champ renvoie une liste. Elle ne peut pas déterminer si cette liste s’agrandit en fonction des entrées de l’utilisateur et nécessite donc une pagination. Un modèle peut lire le résolveur, le comparer aux exemples présents dans la politique, et expliquer pourquoi le champ correspond ou non au modèle.

    Cette explication vaut plus que le chiffre qui l’accompagne. Lorsqu’un champ est signalé, l’équipe en charge doit savoir pourquoi, afin de pouvoir déterminer rapidement si le problème est réel et, dans l’affirmative, comment planifier la migration. Un score sans explication ne crée que d’autres files d’attente pour le tri.

    Limites à prendre en compte

    La revue par un LLM ne remplace pas la responsabilité liée à l’API ni le jugement du concepteur humain ; il est donc utile d’être clair sur ce qui reste :

    • Les faux positifs continuent de se produire.
  • Parfois, la mise en œuvre seule ne révèle pas l’ensemble de la situation, par exemple lorsque une contrainte se trouve dans un autre service.
  • Les contraintes liées au produit peuvent faire en sorte qu’une forme imparfaite constitue malgré tout le compromis approprié.
  • Le système ne migre pas automatiquement les clients ni ne rend les modifications risquées sûres. Il identifie simplement les dettes techniques ; les équipes doivent toujours planifier et exécuter les migrations avec soin.
  • Ce qu’il offre, en revanche, c’est une méthode scalable pour mettre en évidence des schémas qui étaient auparavant limités par la quantité de révision humaine disponible. Les directives sont codées une seule fois, appliquées de manière cohérente dans tous les dépôts, et les résultats fournissent aux équipes un point de départ factuel pour leurs discussions de conception.

    Conclusion

    Le système se compose de deux parties qui partagent la même idée. Lors d’une demande de fusion, un évaluateur basé sur un LLM applique les directives de conception aux nouvelles modifications du schéma avant que les clients ne s’y fient. En mode batch, le même système évalue le schéma existant sur une échelle de 1 à 5 ; ces scores sont regroupés dans des tableaux de bord par équipe, et un mécanisme de contrôle continue empêche l’augmentation totale des scores, tandis que les seuils se resserrent avec le temps. Il ne s’agit pas d’une gouvernance entièrement automatisée, et ce n’est pas son but. Il rend la qualité de l’API suffisamment visible pour que les équipes puissent y agir, et il offre à l’équipe de la plateforme un circuit de retour d’information permettant d’améliorer ses propres règles à mesure que cette approche s’étend à davantage parties du schéma.