Die Todesstern-Versionsbeschränkung

Die Todesstern-Versionsbeschränkung

PHPUnit 6, eine neue Hauptversion des De-facto-Standards für das Testen von PHP-basierter Software, wurde kürzlich veröffentlicht. Kurz darauf funktionierten die Tests von Entwicklern, die noch nicht auf die neue Version umsteigen wollten, nicht mehr. Was war passiert?

Diese PHP-Entwickler wurden von den Konsequenzen der Verwendung der „Todesstern-Versionsbeschränkung“ in ihrer composer.json-Datei, dem *-Operator, überrascht.

Sehen Sie, weder * noch unbeschränkte Bereiche wie >= 1.0 können wirklich als Versionseinschränkungen betrachtet werden.

Wenn Sie

{ "require-dev": { "phpunit/phpunit": "*" } }

oder

{ "require-dev": { "phpunit/phpunit": ">= 4.8" } }

verwenden, dann fragen Sie nach Problemen, da Sie Composer anweisen, die neueste Version von PHPUnit zu installieren. Dies könnte eine neue Hauptversion sein, wie es bei PHPUnit 6.0.0 der Fall war, die nicht abwärtskompatibel ist und die Ihre Tests ohne Migrationsaufwand nicht ausführen kann.

Semantic Versioning

Die meisten Komponenten, die Sie per Composer installieren können, verwenden Semantic Versioning. Kurz gesagt bedeutet dies, dass Sie sich bei der Interpretation ihrer Versionsnummern auf die folgenden drei einfachen Regeln verlassen können:

  • Die Hauptversion wird inkrementiert, wenn es inkompatible Änderungen gibt, beispielsweise wenn sich die öffentliche API ändert. PHPUnit zum Beispiel erhöht die Hauptversion auch, wenn es die Unterstützung für eine PHP-Version einstellt, die zuvor unterstützt wurde
  • Die Minor-Version wird inkrementiert, wenn neue Funktionalität abwärtskompatibel hinzugefügt wird
  • Die Patch-Version wird inkrementiert, wenn Fehler rückwärtskompatibel behoben werden

Composer unterstützt die Idee der semantischen Versionierung durch den Caret-Operator (^):

{ "require-dev": { "phpunit/phpunit": "^5.7" } }

Mit der oben gezeigten Versionseinschränkung ^5.7 weisen Sie Composer an, die neueste Version von PHPUnit zu installieren, die mit PHPUnit 5.7 abwärtskompatibel ist.

Abhängigkeiten frisch halten

Vor ein paar Jahren habe ich geschrieben:

Es ist sehr sinnvoll, bei der Entwicklung Ihrer Software Komponenten von Drittanbietern zu verwenden. Wenn Sie jedoch eine Komponente verwenden, die nicht (ausreichend) getestet ist, gehen Sie das gleiche Risiko ein wie der Koch, der eine Fertigsauce aus dem Supermarkt verwendet. Sie wissen nicht genau, was der Code der Komponente tut. Für den „Happy Path“ mag sie gut funktionieren. Aber was ist mit den Randfällen? Noch schlimmer ist es, eine Komponente eines Drittanbieters zu verwenden, die nicht mehr gewartet wird. Sie mag heute gut funktionieren. Aber wird sie auch noch funktionieren, wenn beispielsweise eine neue Version von PHP veröffentlicht wird?

Was ich damals geschrieben habe, ist immer noch gültig. Aber es gibt einen Punkt, den ich damals nicht gemacht habe: Halten Sie Ihre Abhängigkeiten frisch. Als die aktive Unterstützung für PHP 5 endete schrieb ich:

Ein Upgrade der von Ihnen verwendeten PHP-Version darf kein seltenes Ereignis sein, vor dem Sie sich fürchten. Sie dürfen das Upgrade Ihres PHP-Stacks nicht als „besonderes Projekt“ betrachten. Sie müssen das Upgrade der von Ihnen verwendeten PHP-Version zu einem Teil Ihrer normalen Arbeitsabläufe machen und den Upgrade-Zyklus Ihres PHP-Stacks mit dem Release-Zyklus des PHP-Projekts abstimmen.

Das Gleiche gilt für alle Komponenten von Drittanbietern, die Sie verwenden: Halten Sie sie frisch, um Ihre Software gesund zu halten.

Wenn Sie Composer verwenden, um die Abhängigkeiten Ihres Projekts zu verwalten, sollten Sie folgende Versionsbeschränkung verwenden:

{ "require-dev": { "phpunit/phpunit": "^6.0" } }

Mit dieser Konfiguration installiert der Composer immer die neueste Version von PHPUnit, die mit PHPUnit 6.0 kompatibel ist.

Dies stellt sicher, dass Sie „frisch“ bleiben, solange PHPUnit 6 die aktuelle stabile Version von PHPUnit ist und neue Nebenversionen wie PHPUnit 6.1 enthält. Und wenn die Zeit kommt und PHPUnit 7 veröffentlicht wird, wird Composer es nicht automatisch und unerwartet installieren.

Das Upgraden einer Abhängigkeit auf eine neue Hauptversion muss eine bewusste Entscheidung sein, die Teil eines definierten Prozesses ist. Dieser Prozess sollte zumindest das Lesen des ChangeLogs beinhalten.