Semantische Versionierung beim Beheben eines wichtigen Fehlers

18

Ich verwalte derzeit eine Bibliothek, die viel öffentlich genutzt wird, und ich hatte eine Frage zur semantischen Versionierung . Ich möchte einen ziemlich wichtigen Teil der Bibliothek umgestalten, der falsch implementiert ist - und immer falsch implementiert wurde. Dies würde jedoch Änderungen an der öffentlichen API bedeuten, was eine wichtige Entscheidung ist.

Die Änderung, die ich vornehmen möchte, dreht sich darum, wie Iteratoren verwendet werden. Derzeit müssen Benutzer dies tun:

while ($element = $iterator->next()) {
   // ...
}

Was zumindest in der nativen Iterator-Oberfläche von PHP nicht stimmt . Ich möchte Folgendes ersetzen:

while ($iterator->valid()) {
   $element = $iterator->current();
   // ...
   $iterator->next();
}

das ist analog zu:

foreach ($iterator as $element) {
    // ...
}

Wenn Sie sich Toms Handbuch zur semantischen Versionierung ansehen, stellt er klar, dass alle Änderungen an der öffentlichen API (dh diejenigen, die nicht abwärtskompatibel sind) eine Hauptversion rechtfertigen sollten. Die Bibliothek würde also von 1.7.3 auf 2.0.0 springen, was für mich ein Schritt zu weit ist. Wir sprechen nur über ein Feature, das repariert wird.

Ich habe vor, irgendwann 2.0.0 herauszubringen, aber ich dachte, dies war der Zeitpunkt, an dem Sie die Bibliothek komplett neu geschrieben und zahlreiche öffentliche API-Änderungen vorgenommen haben. Ist für die Einführung dieses Refactorings eine Hauptversion erforderlich? Ich kann wirklich nicht sehen, wie es funktioniert - ich fühle mich wohler, wenn ich es als 1.8.0 oder 1.7.4 veröffentliche. Hat jemand einen Rat?

hohner
quelle
Was hindert Sie daran, die Abwärtskompatibilität beizubehalten?
Mouviciel
Derzeit wird die next()Methode verwendet, um das aktuelle Element abzurufen UND den internen Zeiger vorwärts zu bewegen. Was falsch ist. next()sollte den Zeiger bewegen, und current()wird verwendet, um abzurufen ...
Hohner
6
In der neuen Version sollten sich die Leute also nicht um den Rückgabewert von next()nur dem kümmern, der den Zeiger bewegt, das bricht wirklich nicht die Kompatibilität
Ratschenfreak

Antworten:

29

Sie zögern, weil Sie keine semantische Versionierung vornehmen möchten, sondern "Werbung zur Unterstützung der Versionierung". Sie erwarten, dass die Versionsnummer "2.0" der Welt mitteilt, dass Ihre Bibliothek eine Reihe neuer cooler Funktionen enthält, und nicht, dass Sie die API geändert haben. Das ist in Ordnung (viele Softwareunternehmen und / oder Entwickler machen das). IMHO haben Sie folgende Möglichkeiten:

  • halte dich an die semantische Versionierung und lebe mit der Tatsache, dass du die Versionsnummer auf 2.0.0 ändern musst
  • Ändern Sie Ihr Versionsschema in 4 Zahlen. "1.1.7.3" ist jetzt Ihre Version, "1.2.0.0" die nächste nach Änderung der API und "2.0.0.0" die erste aus der "völlig neuen 2.x-Produktfamilie".
  • Machen Sie Ihr Update abwärtskompatibel (ändern Sie also nicht die Funktionalität von next, sondern fügen Sie einfach die Funktionen validund hinzu current). Dann können Sie "1.8.0" als nächste Versionsnummer verwenden. Wenn Sie der Meinung sind, dass das Ändern des Verhaltens von nextwirklich wichtig ist, führen Sie es in 2.0.0 aus.
Doc Brown
quelle
So viel wie die letzte Option die perfekte Lösung wäre: Sie können nicht darum bitten next(), das zu tun, was es tut. Um die Funktionalität korrekt zu implementieren, muss etwas anders gemacht werden. Wenn ich es also abwärtskompatibel mache, ist die neue Funktionalität / Korrektur ebenfalls falsch und untergräbt den gesamten Punkt der Änderung.
Hohner
2
Der weiter gefasste Vorschlag, den Sie in Ihrem dritten Aufzählungszeichen machen (um die Korrektur abwärtskompatibel zu machen), ist eine gute Überlegung. In diesem speziellen Fall funktioniert es möglicherweise nicht, aber die gesamte Technik ist eine Überlegung wert. Die Funktion wird komplexer, aber dies kann eine praktikable Route sein.
Vielen Dank an alle: Wenn ich zwei akzeptieren könnte, würde ich. Am Ende habe ich die neue next()Methode gehackt , um alle neuen Funktionen zu nutzen, und auch, was erforderlich war, um die Abwärtskompatibilität zu gewährleisten. Es fühlt sich irgendwie schrecklich an, neue Funktionen wie diese trüben zu müssen, aber hey ho.
Hohner
10
@hohner: Dann ist es jetzt auch an der Zeit, das alte Verhalten als veraltet zu dokumentieren, sodass Sie es in 2.0.0 entfernen können.
Jan Fabry
7

Halten Sie sich an Toms Leitfaden zur semantischen Versionierung.

Jede wesentliche Änderung an einer öffentlichen API muss an einem der beiden Punkte vorgenommen werden:

  1. noch nie
  2. Bei einem Major Release Update

Meine Stimme ist übrigens für die erste. Aber ich gebe zu, dass es nur für Kleinigkeiten geeignet ist.

Das Problem besteht darin, die Abwärtskompatibilität aufrechtzuerhalten und sicherzustellen, dass die vorherigen Benutzer Ihrer API keine Probleme haben.

Im Wesentlichen erstellen Sie einen Indizierungsfehler für Ihre Benutzer, die die Änderung nicht kennen. Wenn Sie eine solche Änderung erzwingen, müssen alle Benutzer die folgenden Schritte ausführen:

  1. Codieren Sie das Update, um den neuen Ansatz zu verwenden
  2. Überprüfen Sie den Fix und stellen Sie sicher, dass nichts kaputt ist
  3. Versenden Sie neue Versionen ihres Produkts an ihre Endbenutzer

Dies kann möglicherweise eine Menge Aufwand bedeuten, insbesondere wenn Sie berücksichtigen, wie wenige Projekte Testfälle haben, um solche Änderungen zu validieren. Der Aufwand ergibt sich aus der Anzahl der nachgeschalteten Benutzer Ihrer Benutzer, deren Installationen ebenfalls aktualisiert werden müssen.

Für etwas so Kleines würde ich es loslassen und mich nicht darum kümmern.
Wenn es dich wirklich stört (was es anscheinend tut oder du nicht gefragt hättest), dann würde ich folgendes tun.

  1. Erstellen Sie den Zweig v2.0.0 in Ihrem Codebaum
  2. Machen Sie den ersten Beitrag zum Zweig v2.0.0, bei dem es sich um diese Änderung handelt
  3. Senden Sie eine Vorschau, Release Notesbevor Sie die Änderung bekannt geben

Und dann haben Sie etwas Geduld, denn es wird eine Weile dauern, bis Sie andere Dinge gefunden haben, die ein Upgrade der Versionsnummer auf eine neue Hauptversion rechtfertigen. Die erweiterte Benachrichtigung (Teil 3) gibt Ihnen Zeit, Feedback von Endbenutzern zu erhalten, um herauszufinden, wie stark sich die Änderung auswirken wird.


Eine alternative Lösung besteht darin, eine neue Funktion hinzuzufügen, die wie gewünscht funktioniert.

Wenn ja foo(), würden Sie erstellen fooCorrect(), um das Update bereitzustellen, aber auch die Abwärtskompatibilität vollständig zu erhalten. Und irgendwann können Sie es ablehnen foo(), wenn andere wissen, dass Sie es nicht verwenden sollen.

Die Herausforderung besteht, dass Sie finden etwas anderes in fooCorrect()dem erfordert es das Update und Sie am Ende mit fooCorrectedCorrect()oder einigen anderen Dummheiten.

Wenn Sie dies jetzt wirklich korrigieren möchten , ist dieser alternative Ansatz wahrscheinlich die beste Route. Seien Sie sich bewusst und seien Sie vorsichtig, wenn Sie auf diese Weise viele zusätzliche Funktionen erstellen, da dies die Arbeit mit der API erschwert. Und dieses Bewusstsein könnte ausreichen, um die schlimmsten Probleme dieser Art zu verhindern.

Dies könnte jedoch der "am wenigsten schlechte" Ansatz sein, der für etwas Kleines in Betracht gezogen werden sollte.


quelle
Ich stimme mit Ihnen ein. Das Problem ist, dass ich die Bibliothek für v2.0.0 komplett neu schreiben möchte (da viele dieser Probleme behoben werden müssen). Ich möchte also nicht, dass eine so kleine Änderung wie Iteratoren die Grundlage für diese große Änderung bildet. Meine Optionen sind also entweder: Ignoriere diesen Fehler oder behebe den Fehler und stelle ihn in eine neue Hauptversion?
Hohner
@hohner - aktualisierte Antwort, um einen alternativen Ansatz zum Erstellen neuer Funktionen bereitzustellen. Beachten Sie, dass viele neue Funktionen mit ähnlichen Namen fast so schlimm sind wie das Ändern der API.
3
@hohner: Konsequent falsch> inkonsistent richtig in diesem Fall. Das Verhalten funktioniert immer noch, es ist einfach nicht idiomatisch. Bedenken Sie, dass wenn Sie diese Änderung vornehmen Sie brechen Client - Code. Dies ohne Vorwarnung zu tun, wird nicht gewürdigt.
Phoshi
@ GlenH7 In diesem Fall funktioniert die Verwendung einer alternativ benannten Methode nicht. Der native Iterator von PHP basiert auf diesen Methoden (dh next()nicht nextCorrect()). Ich werde sehen, ob ich next () so modifizieren kann, dass es abwärtskompatibel ist UND bei der Implementierung der IteratorSchnittstelle funktioniert .
Hohner
1
@Phoshi Du bist genau richtig - da stimme ich jetzt vollkommen zu. Jetzt ist es Zeit, das Unmögliche zu versuchen und
hohner 28.11.13