Semantische Versionsnumerierung 2.0.0
Martin Kunkel
- softwareentwicklung
Hat man eine Versionsnummer in der Form MAJOR.MINOR.PATCH, dann erhöht man
Zusätzliche Kennzeichnungen für Vorabversionen und Build-Informationen können ergänzend zum Format HAUPT.NEBEN.PATCH verwendet werden.
In der Welt der Softwareverwaltung gibt es eine böse Falle, nämlich die "Hölle der Abhängigkeiten". Je umfangreicher ein System wird und je mehr Pakete man in seine Software integriert, desto wahrscheinlicher ist es, dass man sich eines Tages verzweifelt in dieser Hölle wiederfindet.
Bei Systemen mit vielen Abhängigkeiten kann die Herausgabe eines neuen Pakets schnell zum Alptraum werden. Sind die Abhängigkeiten zu eng festgelegt, besteht die Gefahr einer Versionsblockade (nämlich dann, wenn es nicht möglich ist, ein Paket zu aktualisieren, ohne auch sämtliche abhängigen Pakete mit zu aktualisieren). Sind die Abhängigkeiten dagegen zu unscharf festgelegt, wird man sich unweigerlich in einem Durcheinander von Versionen verlieren (wenn man die Kompatibilität mit zukünftigen Versionen großzügiger festlegt als es gut wäre). Die Hölle der Abhängigkeiten hat man erreicht, wenn eine Versionsblockade oder die Kombination der vorliegenden Versionen eine einfache und sichere Aktualisierung des Projekts unmöglich macht.
Als Lösung für dieses Problem schlage ich ein paar simple Regeln vor, welche festlegen, wie Versionsnummern einer Software vergeben und erhöht werden sollten. Diese Regeln basieren auf gängigen und verbreiteten Verfahren, die sowohl in proprietärer als auch quelloffener Software verwendet werden, gehen aber auch darüber hinaus.
Damit dieses System funktioniert, muss man zunächst eine Schnittstelle (API) definieren und veröffentlichen. Das kann in einer förmlichen Dokumentation geschehen oder auch implizit durch den Code selbst. Unabhängig davon ist es wichtig, dass diese Schnittstelle klar und präzise beschrieben ist. Ist sie einmal festgelegt, markiert man Änderungen mit festgelegten Erhöhungen der Versionsnummer. Betrachten wir eine Versionsnummer der Form X.Y.Z (MAJOR.MINOR.PATCH): Fehlerkorrekturen, die die Schnittstelle nicht betreffen, erhöhen die Patchnummer; abwärtskompatible Änderungen oder Erweiterungen der Schnittstelle erhöhen die Nebenversionsnummer; Änderungen der Schnittstelle, die nicht mehr voll abwärtskompatibel sind, erhöhen die Hauptversionsnummer.
Ich nenne dieses System "semantische Versionsnumerierung" (Semantic Versioning). Mit diesem System vermittelt die Versionsnummer und die Art, wie sie fortgezählt wird, eine Bedeutung für den damit beschriebenen Code und den Umfang der Änderungen von einer Version zur nächsten.
Die Schlüsselworte MUSS, DARF NICHT, NOTWENDIG, SOLL, SOLL NICHT, SOLLTE, SOLLTE NICHT, EMPFOHLEN, KANN und OPTIONAL sind in diesem Dokument so zu interpretieren wie in RFC 2119 beschrieben.
Der Gedanke ist nicht neu, schon gar nicht revolutionär. Wahrscheinlich verwenden Sie sogar schon etwas, das dem ziemlich nahe kommt. Aber "ziemlich nahe" ist nicht gut genug. Wenn man sich nicht gewissenhaft an irgendeine formale Spezifikation hält, sind Versionsnummern letztendlich unbrauchbar, um Abhängigkeiten zu beherrschen. Wenn man den beschriebenen Ideen einen Namen gibt und sie klar beschreibt, wird es leicht, den Nutzern Ihrer Software Ihre Absichten mitzuteilen. Sobald diese Absichten klar sind, kann man Abhängigkeiten flexibel (aber nicht zu flexibel) handhaben.
Ein einfaches Beispiel soll zeigen, wie die Hölle der Abhängigkeiten durch den Einsatz semantischer Versionsnumerierung der Vergangenheit angehört. Betrachten wir eine Bibliothek namens "Feuerwehrauto". Sie erfordert ein semantisch numeriertes Paket namens "Leiter". Zum Zeitpunkt, da "Feuerwehrauto" erzeugt wird, liegt "Leiter" in der Version 3.1.0 vor. Da "Feuerwehrauto" Funktionen verwendet, die erst mit Version 3.1.0 von "Leiter" eingeführt wurden, kann man mit gutem Gewissen festlegen, dass "Leiter" in Version 3.1.0 oder höher, aber niedriger als 4.0.0 erforderlich ist. Wenn nun "Leiter" in Version 3.1.1 oder 3.2.0 verfügbar ist, kann man sie in das Paketverwaltungssystem einpflegen und sicher sein, dass sie mit der vorhandenen, davon abhängigen Software kompatibel ist.
Als verantwortungsbewusster Entwickler möchte man natürlich sicherstellen, dass jedes Update wie beschrieben funktioniert. Die Welt da draußen ist aber chaotisch; dagegen können wir nichts tun, wir müssen also auf der Hut sein. Man kann aber auf eine semantische Versionsnumerierung setzen und damit seine Pakete auf eine vernünftige Art veröffentlichen und aktualisieren, ohne jedes mal auch die abhängigen Pakete aktualisieren zu müssen und sich so Zeit und Ärger ersparen.
Wenn sich das alles erstrebenswert anhört, müssen Sie nur anfangen, die semantische Versionsnumerierung zu nutzen, indem Sie einfach behaupten, dies zu tun und dann die vorgeschlagenen Regeln einhalten. Setzen Sie in Ihrer README-Datei einen Link zur Website http://www.semver.org/ oder auf dieses Dokument, sodass auch andere die Regeln kennenlernen und davon profitieren können.
Wie sollte ich in der Frühphase der Entwicklung, solange ich Version 0.Y.Z habe, mit Änderungen verfahren?
Das Einfachste ist, wenn Sie ihre Entwicklung mit 0.1.0 beginnen und für jede noch nicht stabile Version, die Sie herausgeben, die Nebenversionsnummer erhöhen.
Woher weiß ich, wann ich Version 1.0.0 erklären soll?
Wenn Ihre Software bereits produktiv genutzt wird, sollte sie wahrscheinlich schon in der Version 1.0.0 vorliegen. Wenn Sie eine stabile Schnittstelle haben, auf die sich die Anwender schon verlassen, sollten Sie mindestens bei 1.0.0 sein. Wenn Sie sehr um Abwärtskompatibilität besorgt sind, sollten Sie wohl ebenfalls schon bei Version 1.0.0 sein.
Hemmt das nicht eine rasche Entwicklung und schnelle Aktualisierungen?
Die Hauptversionsnummer 0 ist gleichbedeutend mit rascher Entwicklung. Wenn Sie die Schnittstelle täglich ändern, sollten Sie entweder noch Version 0.y.z haben, oder an einem separaten Entwicklungszweig arbeiten, der auf die nächsthöhere Hauptversionsnummer abzielt.
Wenn schon die kleinste nicht abwärtskompatible Änderung eine Erhöhung der Hauptversionsnummer bedeutet, lande ich dann nicht ganz schnell bei Version 42.0.0?
Das ist eine Frage von verantwortungsvoller Entwicklung und Weitsicht. Nicht abwärtskompatible Änderungen an Software mit vielen Abhängigkeiten sollten nicht leichtfertig durchgeführt werden. Der Aufwand für eine Aktualisierung kann erheblich sein. Wenn Sie für die Veröffentlichung von nicht abwärtskompatiblen Änderungen die Hauptversionsnummer erhöhen müssen, sollten Sie die Tragweite Ihrer Änderungen und das Verhältnis von Aufwand zum Nutzen bedenken.
Die Dokumentation der Schnittstelle ist zuviel Arbeit!
Es liegt in Ihrer Verantwortung als professioneller Entwickler, die Software, die von anderen benutzt werden soll, sorgfältig zu dokumentieren. Software in all ihrer Komplexität zu beherrschen ist ein äußerst wichtiger Beitrag, um ein Projekt effizient zu halten, und das ist schwierig, wenn niemand weiß, wie Ihre Software zu nutzen ist oder welche Methoden man sicher verwenden darf. Langfristig kann semantische Versionsnumerierung und das Beharren auf klar definierten Schnittstellen dafür sorgen, dass alles reibungslos läuft.
Was mache ich, wenn ich versehentlich eine nicht abwärtskompatible Änderung nur mit einer Änderung der Nebenversionsnummer veröffentlicht habe?
Sobald Sie merken, dass Sie gegen die Spezifikation der semantischen VersionsNumerierung verstoßen haben, beheben Sie das Problem und geben Sie eine neue Nebenversion heraus, die den Irrtum korrigiert und die Abwärtskompatibilität wiederherstellt. Selbst in diesem Fall ist es nicht akzeptabel, einmal herausgegebene Versionen zu modifizieren. Wenn es Ihnen angemessen erscheint, dokumentieren Sie die fehlerhafte Version und informieren Sie Ihre Nutzer über das Problem, so dass sie von der fehlerhaften Version wissen.
Was soll ich tun, wenn ich interne Abhängigkeiten aktualisiere, ohne dass die Schnittstelle davon betroffen ist?
Das sollte man als kompatibel betrachten, da es die öffentlich dokumentierte Schnittstelle nicht betrifft. Der Autor einer Software, die ausdrücklich dieselben Abhängigkeiten hat, wie Ihr Paket, wird jeden Konflikt feststellen, sofern er eine eigene Spezifikation für Abhängigkeiten nutzt. Die Entscheidung, ob eine Änderung nur ein Patch oder eine Änderung im Sinne der Nebenversionsnummer ist, hängt davon ab, ob Sie die Abhängigkeiten wegen einer Fehlerkorrektur oder wegen der Einführung zusätzlicher Funktionalität geändert haben. Ich würde das Ergänzen von weiterem Programmcode normalerweise als letzteres einschätzen, so dass offensichtlich die Nebenversionsnummer erhöht werden sollte.
Was ist, wenn ich versehentlich die Schnittstelle in einer Weise geändert habe, die nicht zur Änderung der Versionsnummer passt (z.B. wenn der Code fälschlicherweise eine wesentliche Änderung in einem Patch-Release einführt)?
Das liegt in Ihrem Ermessen. Wenn Sie ein großes Publikum haben, das von einer Änderung zurück zu dem, was die Versionsnummer widerspiegelt, erheblich betroffen ist, dann ist es möglicherweise das Beste, wenn Sie eine neue Hauptversion veröffentlichen, auch wenn die Korrektur genau genommen nur als Patch einzuordnen wäre. Vergessen Sie nicht, dass es bei der semantischen VersionsNumerierung vor allem darum geht, der Versionsnummer und ihrer Änderung eine Bedeutung zu geben. Wenn Änderungen für Ihre Nutzer wichtig sind, nutzen Sie die Versionsnummer, um diese Information zu vermitteln.
Wie soll ich verfahren, wenn Funktionen wegfallen?
Eine existierende Funktionalität aufzugeben, ist in der Softwareentwicklung ein völlig normaler Vorgang; er ist im Interesse des Fortschritts oft notwendig. Wenn Sie einen Teil der definierten Schnittstelle sterben lassen möchten, sollten Sie zwei Dinge tun: (1) Aktualisieren Sie Ihre Dokumentation, um Ihre Nutzer über die Abkündigung zu informieren, (2) Veröffentlichen Sie eine neue Nebenversion, in der Sie die Abschaffung bereits deutlich machen. Bevor Sie die Funktionalität in einer neuen Hauptversion komplett abschaffen, sollten Sie mindestens eine Nebenversion mit dem Hinweis auf die Abschaffung herausgeben, damit sich Ihre Nutzer ohne Schwierigkeiten auf die neue Schnittstelle umstellen können.
Limitiert SemVer die Länge der Versionsangabe?
Nein, aber handeln Sie überlegt. Eine 255 Zeichen lange Versionsangabe ist vermutlich vollkommen überdimensioniert. Einzelne Systeme könnten auch ihrerseits eine Grenze setzen.
Die Spezifikation für semantische Versionsnumerierung wurde von Tom Preston-Werner verfasst, Erfinder der Gravatars und Mitbegründer von GitHub.
Wenn Sie diesen Artikel im Original kommentieren möchten, eröffnen Sie bitte ein Ticket auf github.
Das Original wurde unter der Creative Commons-Lizenz CC BY 3.0 veröffentlicht.
Die Übersetzung stammt von Martin Kunkel selfhtml@kennst.net. Sie steht ebenfalls unter der Creative Commons Lizenz CC BY 3.0 DE.
Die essentiellen Punkte dieser Lizenz sind
http://blog.selfhtml.org/2013/11/08/semantische-versionsnumerierung-2-0-0/