Versionsnummern sind immer noch ein spannendes Thema, da sich hier die Geister scheiden wie viele Stellen man benutzt und welche Stelle wann hoch gezählt wird. Inzwischen hat sich vor allem im Opensource-Bereich das Dreigestirn aus Major, Minor und Bugfix etabliert und durchgesetzt. D.h. man muss nur noch die Frage klären, wann man die einzelnen Komponenten einer Versionsnummer anfasst.
Üblicherweise hatte man sich früher eher an der Code-Menge orientiert. D.h. kleine Änderung Bugfixnummer hochzählen, mittlere Änderung Minornummer hochzählen und eine sehr umfassende Codeänderung war dann mit einem Anstieg der Majorversionsnummer gleichzusetzen. Dies war dann auch die entsprechende Erwartungshaltung in umgekehrter Sichtweise. Also wenn ich eine Software mit einer höheren Majorversionsnummer einsetze, dann muss sich da aber auch einiges geändert haben etc.
Wie man aus der Beschreibung erkennen kann ist es eine relativ schwammige Definition, wann welche Stelle der Versionsnummer hochgezählt werden sollte. Also gibt es hierfür auch eine Idee die sich Semantic Versioning nennt.
Bei Semantic Versioning handelt es sich um ein paar einfache Regeln, die die Änderung der Versionsnummer klar definieren. Somit hat dann der Entwickler und der Benutzer ein klares Bild, was sich geändert hat.
Der wichtigste Punkt ist, dass man sich von der Code-Mengen Idee löst. Das heißt es ist vollkommen irrelevant wieviel Code geändert wurde, wichtig ist nur welche Konsequenz die Änderung hat. Denn hauptsächlich interessiert mich die API, also die Schnittstelle über die ich die Software nutze.
Die Hauptregeln lassen sich folgendermaßen zusammenfassen:
- Bei inkompatiblen Änderungen der API ist die Major-Version zu erhöhen
- Bei kompatiblen Änderungen der API ist die Minor-Version zu erhöhen
- Bei Fehlerbehebungen ist die Bugfix-Version zu erhöhen
Was heißt das nun in der Praxis?
Wir starten mit einer Bibliothek und geben dieser die Version 1.0.0 (wir sind mit 0.0.0 gestartet und haben die erste Version der API festgelegt, somit haben wir ja eine inkompatible Änderung zur Vorversion 🙂 ).
Nun behebe ich 2-3 Bugs und gebe meine Bibliothek als neue Version heraus. Es handelt sich nur um Fehlerbehebungen und somit bin ich auf Version 1.0.1.
Dann muss ich die API erweitern um eine wichtige Funktion. Das es eine Erweiterung ist, ist sie abwärtskompatibel und ich erhalte jetzt die Version 1.1.0. Eine zweite Erweiterung ist notwendig die ebenfalls abwärtskompatibel ist, also bin ich bei Version 1.2.0.
Nun fällt mir auf, dass einige Methoden der API ineffizient sind und nach dem Refactoring wird eine neue Version mit optimiertem Code bereitgestellt. Da sich die API aber nicht geändert hat bin ich nun bei 1.3.0.
Leider war eine Methode aber nicht sinnvoll und die Parameter machen doch nicht mehr soviel Sinn wie anfangs gedacht. Also kommt es zu einer inkompatiblen Änderung und die neue Version ist die 2.0.0.
Welche Auswirkungen hat dies auf die Versionierung?
Ändert man die API häufig aber immer mit Hinblick auf eine Abwärtskompatibilität kann es zu sehr hohen Minor-Versionen kommen und eine Versionsnummer wie 1.2654.6 ist dann nicht außergewöhnlich.
Arbeitet man jedoch hauptsächlich mit inkompatiblen Änderungen, dann kann man sehr leicht zu einer Version 2654.2.0 gelangen.
Solche Versionsnummern sind zur Zeit noch eher neu, werden aber m.E. mit der Zeit häufiger vorkommen, da Github diese Art der Versionierung empfiehlt.
Fazit
Durch das Semantiv Versioning ist es für den Benutzer leichter ersichtlich, ob er sich eine inkompatible Änderung einhandelt und Abhängigkeiten zwischen Versionen lassen sich auch besser auflösen, da man direkt sehen kann, ab wann eine Inkompatibilität auftreten kann. Die Abwärtskompatibilität gibt dem Benutzer zudem eine viel höhere Sicherheit beim Einsatz einer neuen Version und was eigentlich trivial ist: Die Entscheidung wie die Version der Bibliothek zu lauten hat wird auf eine technische Ebene verschoben und durch klare Regeln definiert. Somit wird nicht mehr nach Gutdünken die Version hochgezählt.