Zurück zum Blog

Abhängigkeits-Updates bewerten: beide Stände installieren statt Changelogs lesen

Bei einem Sprung über achtzehn Minor-Releases einer 0.x-Bibliothek hilft kein Changelog. Wie ich solche Updates in zehn Minuten entscheide: zwei Umgebungen, eine Sonde über die echten Routen, ein Diff — plus die Gegenprobe, die ein altes Lockfile vom Major-Dilemma trennt.

4 Min. Lesezeitvon Daniel AlischEngineering, Development, Automatisierung

Ein Bot hebt eine Bibliothek von 0.143 auf 0.161. Achtzehn Minor-Schritte, ein Stapel Changelog-Einträge, und dahinter immer dieselbe Frage: ändert das etwas an meinem Code? Ich habe mir das Lesen weitgehend abgewöhnt und messe stattdessen. Das ist schneller und, was mehr zählt, es liefert einen Befund statt einer Einschätzung.

Achtzehn Minor-Schritte sind keine Lektüre

Bei einer Bibliothek unterhalb von 1.0 bedeutet ein Minor-Sprung nicht, was man sich wünscht. Die Autoren dürfen in jedem Schritt Verhalten ändern, und sie tun es. Wer den Sprung über achtzehn Releases beurteilen will, liest also achtzehn Einträge, von denen die meisten mit Formulierungen wie „kann sich auswirken, wenn" arbeiten.

Das Ergebnis dieser Lektüre ist eine Vermutung. Ein Changelog beschreibt, was dem Autor erwähnenswert erschien — nicht, was in meinem Projekt passiert. Genau die Änderung, die mich trifft, weil ich eine Fehlerantwort an einer unüblichen Stelle auswerte, ist für den Autor kein Thema. Und die drei Absätze, die ich besorgt dreimal lese, betreffen eine Funktion, die ich nie aufrufe.

Zwei Stände, eine Sonde

Das Vorgehen, das bei mir trägt, braucht keine zehn Minuten. Ich lege zwei virtuelle Umgebungen an, eine mit dem alten, eine mit dem neuen Stand. Wichtig ist dabei nur eine Regel: alle anderen Festlegungen des Projekts bleiben unverändert. Wer beim Anlegen der zweiten Umgebung nebenbei noch zwei Pins auffrischt, misst anschließend deren Nebeneffekt und schreibt ihn der Bibliothek zu.

Dann schreibe ich eine Sonde. Sie fährt die echten Routen meiner Anwendung — nicht ein Hallo-Welt-Beispiel aus der Dokumentation — und druckt am Ende einen stabilen Fingerabdruck als JSON: sortierte Schlüssel, gerundete Zahlen, keine Zeitstempel, keine Zufallswerte.

python
import json
from fastapi.testclient import TestClient
from app.main import app

client = TestClient(app)
fingerprint = {}

for method, path, body in [
    ("GET", "/health", None),
    ("POST", "/items", {"name": "probe"}),
    ("POST", "/items", {}),            # absichtlich ungueltig
]:
    r = client.request(method, path, json=body)
    fingerprint[f"{method} {path} {json.dumps(body, sort_keys=True)}"] = {
        "status": r.status_code,
        "keys": sorted(r.json().keys()) if r.headers.get("content-type", "").startswith("application/json") else None,
        "detail_type": type(r.json().get("detail")).__name__ if r.status_code >= 400 else None,
    }

print(json.dumps(fingerprint, indent=2, sort_keys=True, ensure_ascii=False))

Schwere Abhängigkeiten klammere ich aus. Wenn im Dienst ein Modell geladen wird, ersetze ich genau diesen Aufruf durch einen Platzhalter mit konstanter Ausgabe. Die Sonde soll die Schnittstelle messen, nicht ein Gigabyte Gewichte von der Platte holen. Zum Schluss lasse ich beide Ausgaben gegeneinander laufen — ein schlichtes diff genügt — und habe damit schwarz auf weiß, ob sich an der Oberfläche, an der mein Code hängt, etwas bewegt hat.

Was der Vergleich beantwortet, und was nicht

Beantwortet wird: Statuscodes, die Form der Antworten, die Struktur von Fehlermeldungen, das Verhalten der Validierung bei absichtlich falschen Eingaben. Das ist der Teil, an dem fremder Code typischerweise bricht, und zwar leise.

Nicht beantwortet wird alles, was die Sonde nicht anfasst: Laufzeitverhalten unter Last, seltene Pfade, Nebenwirkungen auf Datenbankebene. Deshalb lohnt es sich, die Sonde aus den tatsächlich benutzten Routen zu bauen und dort, wo ein Format nach außen geht, auch das Format zu prüfen — nicht nur den Statuscode. Der Unterschied zur Changelog-Lektüre bleibt bestehen: ein Diff ist ein Befund mit bekannter Reichweite. Eine Lektüre ist eine Meinung mit unbekannter Reichweite.

Die Gegenprobe, die zwei Diagnosen trennt

Der gleiche Reflex hilft an einer zweiten Stelle, an der ich mich schon zweimal selbst in die Irre geführt habe. In einem Projekt meldete die Sicherheitsprüfung des Paketmanagers eine zweistellige Zahl hoher Befunde. Meine eigene Notiz dazu war eindeutig: hängt alles an einer Abhängigkeitskette, lösbar nur über einen Major-Sprung, von dem es bisher nur einen Release-Kandidaten gibt. Das klang nach einer Woche Arbeit.

Die Gegenprobe war eine einzige: das Lockfile auffrischen, ohne eine Zeile in der Paketliste zu ändern. Danach waren fast alle Befunde weg. Es war nie ein Major-Dilemma, es war ein altes Lockfile — und die beiden Zustände erzeugen in der Ausgabe der Sicherheitsprüfung dieselbe Signatur. Man kann sie am Bericht nicht unterscheiden, nur am Experiment. Das Hübsche daran: die Gegenprobe war gleichzeitig der ganze Fix.

Daraus ist bei mir eine feste Reihenfolge geworden. Bevor aus einer Fehlerliste eine Diagnose wird, kommt die billigste Messung, die zwei konkurrierende Erklärungen auseinanderziehen kann. Wenn diese Messung unter fünf Minuten kostet, gibt es keinen Grund, stattdessen zu argumentieren.

Fazit

Beide Fälle sind dieselbe Bewegung: nicht über einen Zustand reden, sondern ihn zweimal herstellen und die Ergebnisse vergleichen. Das Verfahren ist unspektakulär, es erzeugt keine klugen Sätze, und es ist in beiden Fällen schneller gelaufen als der Versuch, sich die Antwort zu erlesen. Wer mit vielen automatisch erzeugten Update-Vorschlägen lebt, braucht ohnehin ein Verfahren, das bei jedem einzelnen davon gleich abläuft. Lesen skaliert nicht. Messen schon.

Weiterlesen