Startseite / Artikel / Bewertung der Schulden im GraphQL-Schema-Design mit LLMs und einem CI-Ratchet

Bewertung der Schulden im GraphQL-Schema-Design mit LLMs und einem CI-Ratchet

Wie man einen LLM-Prüfer sowie eine Bewertung von 1 bis 5 nutzt, um subjektive Probleme im GraphQL-Design in neuen Pull Requests aufzudecken und die bereits vorhandenen Schwächen im Schema zu identifizieren.

1929 Wörter

Ein GraphQL-Schema, das von Dutzenden oder Hunderten von Entwicklern in vielen Produktbereichen geändert wird, entwickelt sich unweigerlich weiter – egal wie gut die Stilrichtlinien auch sein mögen. Linter erkennen mechanische Probleme, doch die kostspieligen Fälle erfordern Urteilsvermögen: Ein String, der eigentlich eine Enum sein sollte, eine Liste, die unbegrenzt wächst, ein optionaler Feld, das niemals tatsächlich null zurückgibt. Dieser Artikel beschreibt ein zweiteiliges System für solche Fälle: einen von einem LLM unterstützten Prüfer, der neue Designschulden bereits bei Pull-Requests verhindert, sowie eine Bewertung des bestehenden Schemas, die alte Schulden in einen priorisierten, nachverfolgbaren Backlog umwandelt, der durch einen CI-Ratchet durchgesetzt wird.

Warum die API-Qualität zu einem Systemproblem wird

Mit nur wenigen Ingenieuren hängt eine konsistente API größtenteils vom gemeinsamen Geschmack ab. Die Leute arbeiten nebeneinander, prüfen die Änderungen an den Schemata voneinander und finden zu denselben Mustern. Wenn die Organisation wächst, funktioniert das nicht mehr. Neue Funktionen werden ständig eingeführt, ältere Konventionen koexistieren mit neuen, und Entscheidungen, die für das ursprüngliche Team offensichtlich waren, werden von Teams, die diese nie getroffen haben, anders umgesetzt.

Zu diesem Zeitpunkt benötigt man Antworten auf drei Fragen, die nicht von der Aufmerksamkeit eines einzelnen Prüfers abhängen:

  • Wie kann man die API-Entwicklung konsistent halten, wenn viele Teams gleichzeitig an den Schemata arbeiten?
  • Wie stellt man sicher, dass neue Typen und Felder den aktuellen Best Practices entsprechen?
  • Wie findet man die Teile der API, die bereits vor dem Bestehen dieser Praktiken entworfen wurden?

Die ersten beiden beziehen sich auf Prävention. Der dritte befasst sich mit Archäologie und wird von den meisten Governance-Bemühungen übersprungen.

Wo die Linter-Regeln aufhören und das Urteilsvermögen beginnt

Ein großer Teil der API-Standards ist mechanischer Natur, und statische Analyse kann sie gut bewältigen. Namenskonventionen, die Verwendung von veralteten Feldern, obligatorische Beschreibungen sowie ein konsistentes Fehlerformat sind allesamt Ja-oder-Nein-Eigenschaften des Schemas: Ein Feld folgt entweder der Regel oder nicht, und ein Linter kann das feststellen.

Andere Standards lassen sich nicht auf einfache Regeln reduzieren. Typische Beispiele:

  • Soll dieser String eine Enum sein?
  • Soll diese Liste paginiert werden?
  • Soll dieser Int ein benutzerdefinierter Skalar sein?
  • Kann dieses nullable-Feld sicherlich nicht-nullable werden?
  • Passt diese Struktur zu der Darstellung ähnlicher Konzepte an anderen Stellen der API?

Eine dieser Fragen lässt sich nicht ohne Kontext beantworten. Das Zurückgeben einer String-Wert oder sogar eines untypisierten JSON-Objekts ist manchmal korrekt. Um festzustellen, ob dies tatsächlich richtig ist, müssen drei Aspekte zusammen betrachtet werden: die Schema-Deklaration, die dahinterliegende Implementierung des Lösers sowie der Zweck hinter der Bereitstellung dieser Daten an Clients. Nur mit allen drei Aspekten lässt sich beurteilen, welche Form den Clients am besten dient.

Organisationen handhaben dies in der Regel durch Code-Reviews, Sprechstunden mit dem Plattformteam sowie schriftliche Richtlinien. Das funktioniert, ist aber schwer skalierbar. Zeitdruck verkürzt die Reviews, das Plattformteam kann nicht jede Schema-Änderung in jedem Repository prüfen, und Best Practices entwickeln sich schneller, als alte APIs erneut überarbeitet werden. Das führt zu zwei zusammenhängenden Problemen: dem Verhindern neuer Designschulden sowie der Aufdeckung bereits vorhandener Schulden.

Shifting left: Ein LLM-Reviewer für Schema-Änderungen

Der erste Teil des Systems kodiert die Richtlinien für das API-Design in einen automatisierten Code-Review-Agenten. Ziel ist es nicht, menschliche Reviewer zu ersetzen, sondern ihnen eine zweite Überprüfungssicht auf genau die Probleme zu bieten, die bei einer normalen Pull-Request-Überprüfung übersehen werden. Dass das Platform-Team persönlich jede GraphQL-Änderung in allen Repositorien freigibt, ist nicht skalierbar; die Einführung der bevorzugten Standards in einen überall laufenden AI-Reviewer hingegen schon.

Weil der Agent mehr sieht als nur die Schema-Differenzen, kann er im Kontext statt in der Syntax argumentieren. Er liest die Deklaration, die Implementierung, die das Feld unterstützt, sowie den relevanten Richtlinientext und stellt anschließend spezifische Fragen. Zwei repräsentative Kommentare:

  • Ein Feld mit dem Namen updatedAt wird als String deklariert. Wenn der Resolver einen ISO 8601-Zeitstempel zurückgibt, sollte er vermutlich stattdessen den speziellen Skalar ISO8601DateTime verwenden.
  • Company.employees gibt eine einfache Liste zurück. Die Belegschaft eines Unternehmens hat keine natürliche Obergrenze, daher sollte dieses Feld eine paginierte Ansicht liefern.

Niemandes von diesen Fällen kann zuverlässig von einem Linter erkannt werden. Eine Lint-Regel, die besagt „Felder, die auf At enden, müssen Datums-Skalare sein“, erzeugt falsch-positive Ergebnisse und übersieht lastModified; eine Regel, die besagt „alle Listen müssen paginiert sein“, ist für ein Feld falsch, das eine der drei unterstützten Währungen zurückgibt. Der LLM kann prüfen, was der Resolver tatsächlich tut.

Der Schlüssel liegt im richtigen Zeitpunkt. Solche Probleme zu erkennen, solange die API noch entworfen wird, ist kostengünstig. Wenn sie erst nach der Einführung durch die Kunden entdeckt werden, bedeutet das einen Deprecierungszyklus und eine Migration.

Rückblick: Bewertung des bereits vorhandenen Schemas

Prävention nützt bei der bereits bestehenden Komplexität nichts – und in einer ausgereiften API ist diese Komplexität groß. Ein Teil davon stammt noch von vor den aktuellen Standards. Teile davon spiegeln Kompromisse wider, die zu ihrer Zeit sinnvoll waren. Weitere Teile sind einfach ungleichmäßig, weil verschiedene Teams dasselbe Konzept auf ihre eigene Weise modelliert haben. Man benötigt daher eine Möglichkeit, rückblickend zu betrachten.

Der zweite Teil des Systems ist ein Batch-Prozess, der die bereits vorhandenen Tools zur statischen Analyse ergänzt. Sein Ablauf ist wie folgt:

  1. Man durchläuft das Schema Gebiet für Gebiet und wählt Felder oder Typen aus, bei denen subjektive Designentscheidungen relevant sind.
  • Sammeln Sie die Schema-Deklaration zusammen mit dem entsprechenden Implementierungscode.
  • Schicken Sie diesen Kontext an ein LLM in einem Prompt, der die schriftlichen API-Design-Richtlinien enthält.
  • Fragen Sie das Modell, ob das Feld einer dieser subjektiven Richtlinien zuwiderzulaufen scheint.
  • Speichern Sie das Ergebnis als Wert zusammen mit einer schriftlichen Erklärung.
  • Fassen Sie die Ergebnisse nach Produktbereich oder zuständigem Team zusammen.
  • Schritt 1 ist wichtig für Kosten und Informationsmengen. Es gibt keinen Grund, ein Modell nach Feldern zu fragen, die bereits durch eine deterministische Überprüfung klassifiziert wurden; das LLM sollte nur die Fälle betrachten, bei denen tatsächlich ein Urteil erforderlich ist.

    Warum eine 1-bis-5-Skala besser ist als Erfolg/Niederlage

    Da es sich um urteilsbedürftige Entscheidungen handelt, führt das Zwängen jedes Ergebnisses in ein binäres Urteil dazu, dass Informationen verloren gehen. Stattdessen erhält jedes Feld eine Bewertung von 1 bis 5:

    • 1: Das Feld sieht wie vorgesehen geeignet aus.
    • 2: Es gibt ein schwaches Signal, aber es ist vermutlich in Ordnung.
    • 3: Ein Mensch sollte nachsehen.
    • 4: Das Feld verstößt wahrscheinlich gegen die Richtlinien.
    • 5: Das Feld ist ein typisches Beispiel für das Muster, das vermieden werden sollte.

    Konkret ausgedrückt: Ein String-Feld, das beliebigen vom Benutzer eingegebenen Text enthält, sollte bei 1 liegen. Ein String-Feld mit dem Namen errorCode, dessen Resolver nur immer einen von drei fest programmierten Werten zurückgeben kann, sollte bei 5 liegen, da es sich um eine versteckte Enum handelt.

    Eine benotete Bewertung liefert ein weitaus nützlicheres Signal als eine einfache Liste der Verstöße. Teams können mit den hochzuverlässigen Bewertungen 4 und 5 beginnen und gleichzeitig die weniger zuverlässigen Bereiche erkennen, die einer genaueren Prüfung bedürfen könnten. Die Mitte der Skala hat eine weitere Funktion: Eine Gruppe von Bewertungen 3 zeigt dem Plattformteam an, wo die Formulierung der Richtlinie oder die Anfrage unklar ist – das dient als Feedback zur Verbesserung der Bewertungsanfragen, bis zuverlässigere Ergebnisse erzielt werden.

    Falls Sie etwas Ähnliches entwickeln, fordern Sie vom Modell eine strukturierte Ausgabe an (eine Bewertung und eine Erklärung als getrennte Felder), damit die Ergebnisse ohne Auswerten von Prosa gespeichert und zusammengefasst werden können. Halten Sie außerdem den Text der Richtlinie sowie die Versionen der Bewertungskriterien zusammen mit der Anfrage bereit, damit Änderungen in den Bewertungen auf Regeländerungen zurückgeführt werden können.

    Ergebnisse in Handlungen umsetzen

    Werte in einer Datenbank ändern sich von selbst nicht. Durch die Aggregation dieser Werte nach Domänen in einem Dashboard erhält jedes zuständige Team einen klaren Überblick über die API-Design-Schulden in seinem Bereich: nicht nur verstreute Anekdoten oder einzelne Bewertungskommentare, sondern eine priorisierte Liste von Feldern und Typen, die möglicherweise migriert werden müssen.

    Dieselben Daten ermöglichen einen schrittweisen Fortschritt in der kontinuierlichen Integration. Es geht nicht darum, alles auf einmal zu beheben – was bei einer großen API mit vielen Produktionskunden unrealistisch ist –, sondern darum sicherzustellen, dass sich die Situation nicht verschlechtert, während sich die bestehende Struktur im Laufe der Zeit verbessert:

    • Neuere Schema-Änderungen müssen den aktuellen Standard erfüllen.
    • Bestehende Probleme werden als bekannte Schulden dokumentiert, anstatt stillschweigend ignoriert zu werden.
    • Wenn Teams alte Muster migrieren oder deaktivieren, wird die zulässige Schwellenwertgrenze verschärft, sodass bereits behobene Schulden nicht wieder auftauchen können.

    Ratchet-Strategien sind ein bekanntes Muster bei der Migration von Daten: Es wird die aktuelle Anzahl der Verstöße pro Bereich erfasst, der Build fehlschlägt, wenn eine Änderung diese Anzahl erhöht, und der erfasste Basiswert wird gesenkt, sobald jemand ein Problem behebt.

    Dieser Ansatz ist besonders wichtig für öffentliche oder weit verbreitete APIs, bei denen die Bereinigung von Client-Migrationen abhängt. Das Ergebnis ist keine Anweisung, jedes fehlerhafte Feld zu löschen. Es handelt sich vielmehr um eine priorisierte Übersicht darüber, an welchen Stellen die API nicht mehr den aktuellen Standards entspricht, damit Teams entsprechend planen können.

    Warum ein LLM das richtige Werkzeug für diesen Bereich ist

    LLMs sind keine fehlerfreien Beurteiler von API-Design, und das System behandelt sie auch nicht als solche. Ihre Stärke liegt hier in etwas Besonderem: Sie lesen Code und Schemata gemeinsam, vergleichen sie mit in Alltagssprache verfassten Richtlinien und liefern eine strukturierte Bewertung für Fälle, die sich mit statischen Regeln nicht beschreiben lassen.

    Eine statische Regel kann angeben, dass ein Feld eine Liste zurückgibt. Sie kann jedoch nicht feststellen, ob diese Liste durch Benutzereingaben wächst und daher Paginierung erfordert. Ein Modell kann den Resolver lesen, ihn mit den Beispielen in der Richtlinie vergleichen und erklären, warum das Feld dem Muster entspricht oder nicht.

    Diese Erklärung ist wertvoller als die dazugehörige Zahl. Wenn ein Feld markiert wird, muss das zuständige Team wissen, warum, damit es schnell entscheiden kann, ob die Feststellung berechtigt ist – und falls ja, wie die Migration geplant werden soll. Eine Bewertung ohne Begründung führt lediglich zu einer weiteren Warteschlange für die Bearbeitung.

    Beschränkungen, die Sie berücksichtigen sollten

    Die Überprüfung mit LLM ersetzt nicht die Verantwortung für die API oder das urteilsfähige Design von Menschen; es ist daher hilfreich, klar zu benennen, was noch zu tun bleibt:

    • Falschpositive Ergebnisse treten weiterhin auf.
  • Mannchmal zeigt allein die Implementierung nicht das vollständige Bild, zum Beispiel dann, wenn eine Einschränkung in einem anderen Service vorhanden ist.
  • Produkteinschränkungen können dazu führen, dass eine unvollkommene Form dennoch die richtige Abwägung darstellt.
  • Das System migriert keine Clients und macht brisante Änderungen nicht sicher. Es erkennt Verbindlichkeiten; die Teams müssen weiterhin sorgfältig Migrationspläne erstellen und umsetzen.
  • Was es jedoch bietet, ist eine skalierbare Methode, Muster aufzuzeigen, die zuvor durch den verfügbaren Umfang der menschlichen Überprüfung eingeschränkt waren. Leitlinien werden einmal kodiert, konsistent in jedem Repository angewendet, und die Ergebnisse liefern den Teams einen faktischen Ausgangspunkt für Designgespräche.

    Zusammenfassung

    Das System besteht aus zwei Teilen, die denselben Ansatz teilen. Bei Pull-Requests wendet ein LLM-Bewerter die Designrichtlinien auf neue Schema-Änderungen an, bevor Clients davon abhängig werden. Im Batch-Modus bewertet derselbe Bewertungsalgorithmus das bestehende Schema mit 1 bis 5 Punkten; diese Scores werden in Team-Dashboards zusammengefasst, und ein CI-Ratchet verhindert, dass die Gesamtpunktzahl steigt, während die Schwellenwerte im Laufe der Zeit strenger werden. Es handelt sich dabei nicht um eine vollständig automatisierte Governance-Lösung – und das ist auch nicht beabsichtigt. Sie sorgt dafür, dass die API-Qualität deutlich sichtbar wird, sodass Teams darauf reagieren können, und bietet dem Plattformteam einen Feedbackkreislauf, um seine eigenen Regeln weiter zu verfeinern, je mehr Teile des Schemas abgedeckt werden.