In diesem Artikel geht es um die Go Toolchain und das Go Kompatibilitätsversprechen.
Neben den Fixes für die For-Schleifen enthält die Go Version 1.22 einige weitere interessante Anpassungen. Mit der enthaltenen ServerMux-Implementierung kann nun auch ein Pattern-Matching verwendet werden, das bisher nicht möglich war. Zu diesem Thema gibt es viele Artikel und auch die offizielle Dokumentation des http-Package enthält viele Details und Beispiele dazu.
Die gesamte Liste der Änderungen in Go 1.22 lassen sich in den Release-Notes nachlesen. Wer möchte kann es dort nachlesen…
Ich hatte mir die Release-Notes durchgelesen und soweit verstanden. Da wir in Projekten meist mit dem Gin Web Framework gearbeitet haben, hatte ich noch keine Berührung mit den neuen Funktionen des ServerMux.
Da allerdings jetzt eine Microservice-Schulung anstand und wir versuchen die Schulungsunterlagen immer auf dem aktuellen Stand zu halten, und natürlich auch die neuen Features zeigen wollen, war es an der Zeit das bisherige Beispiel zu aktualisieren und das Pattern-Matching aufzunehmen.
Gesagt getan und ich habe das super einfache Einstiegsbeispiel angepasst. Die
Registrierung des Handlers war schnell angepasst und ein GET
vor die
Pfadangabe gesetzt.
http.HandleFunc("GET /", handler)
Ab sofort sollen nur noch, laut Doku, GET und HEAD Anfragen beantwortet werden…. sollen… mmmhhh…
… warum geht das bei allen anderen…. und bei mir nicht….??? Es kam wie es kommen musste und das Feature funktionierte nicht!
In der Dokumentation und in allen Artikeln, die ich gefunden habe, hatte niemand das Problem. Es wurde allerdings eine Option erwähnt, mit der, in einer neuen Go Version, das alte Verhalten konfigurieren werden kann. Und zwar mit der Umgebungsvariablen:
GODEBUG=httpmuxgo121=1
Ich probierte es andersherum und meine Anwendung tat plötzlich was sie sollte. Das Pattern Matching arbeitete wie erwartet.
GODEBUG=httpmuxgo121=0 go run cmd/main.go
ABER ICH HATTE DOCH GO 1.22! … Ok ok, da viel es mir wie Schuppen von den
Augen: Meine go.mod
Datei!
module golang.source-fellows.com/seminar/simple-http
go 1.18
Das Beispiel wurde zum letzten Mal auf Version 1.18 aktualisiert. Und genau hier liegt das Problem (soviel zum Thema die Schulungsbeispiele werden immer aktualisiert - na ja, hier hat sich ja tatsächlich erstmal nichts getan, also kein Anpassungsbedarf).
Eine Anpassung der go.mod
Datei führte erstmals zum erwarteten Verhalten und
die Anwendung verhielt sich so, wie in allen anderen Dokumentationen.
module golang.source-fellows.com/seminar/simple-http
go 1.22.0
Doch was ist im Hintergrund passiert?
In Go Version 1.21 wurde die Nutzung der
Umgebungsvariable GODEBUG
offiziell festgelegt. Mit den hinterlegten Werten
soll das Standardverhalten von Änderungen festgelegt werden, die nach dem
Kompatibilitätsversprechen keine breaking-change darstellen, aber bestehende
Anwendungen trotzdem brechen können.
Beispielsweise könnte eine Anwendung um einen Bug in der Go Standardbibliothek herum gebaut sein und nach dem Fix des Bugs läuft die Anwendung nicht mehr korrekt. Mit der Umgebungsvariablen soll also gesteuert werden ob sich die Go Bibliothek so verhalten soll wie sie es bisher auch getan hat.
Im Hinterkopf hatte man hier sicher die oben angesprochene Änderung der For-Loop.
Das Pattern-Matching aus meinem Beispiel ist ein solcher Fall. In der
Standardbibliothek wurde ein neues Feature aufgenommen, das potenziell
bestehende Anwendungen beeinträchtigen kann. Aus diesem Grund wurde der oben
genannte Wert httpmuxgo121
eingeführt, mit dem das Standardverhalten des
ServerMux konfiguriert werden kann.
Ist der Wert gesetzt (httpmuxgo121=1
), wird das alte (bis Version Go 1.21)
Verhalten eingesetzt, wenn nicht, wird das Verhalten von Go ab Version 1.22
verwendet. Das hatte ich durch das Setzen der Umgebungsvariable bestätigt.
Eine Liste sämtlicher GODEBUG Werte in den verschiedenen Go Versionen findet man auf der Go Webseite. Das sind einige. Zum Beispiel:
tlsmaxrsasize
httplaxcontentlength
tls10server
Jetzt aber zu der Frage was das alles mit der go.mod
zu tun hat.
Ab Go Version 1.21 entscheidet sich die Go Runtime bzw. das Tooling welche
GODEBUG Kompatibilitätseinstellungen standardmäßig verwendet werden sollen und
nutzt hierzu die Information aus der go.work
bzw. go.mod
Datei.
Für jede Go Version gibt es im Hintergrund eine Liste der zugeordneten Kompatibilitätseinstellungen. Im Beispiel in etwa so (nicht alle Versionen sind aufgeführt):
httpmuxgo121=1
httpmuxgo121=1
httpmuxgo121=1
httpmuxgo121=0
Das heißt, steht in der go.mod
eine Versionsangabe, wie in meinem Beispiel die
Version 1.18, wird die Kompatibilität auf diese Version eingestellt und die
GODEBUG Werte entsprechend gesetzt. Die Go Umgebung verhält sich so wie sie sich
in der angegebenen Version verhalten hat bzw hätte.
Für mein Beispiel wurde dementsprechend, da in der go.mod
die Version 1.18
angegeben war, das GODEBUG Flag für httpmuxgo121
automatisch auf 1
gesetzt.
Neue Feature nicht aktiviert. Durch die Umstellung auf 1.22.0 wurde das Flag
automatisch auf 0
gesetzt.
Kompatibilität rocks!
In meinem Fall hatte ich eine neuere Go-Version zur Verfügung. Wenn ich allerdings mit einer alten Go Version die Anwendnung nutzen möchte, tritt ein Kompatibilitätsproblem auf.
Wenn die go.mod
Datei folgende Zeile enthält:
module golang.source-fellows.com/seminar/simple-http
go 1.22.0
und ich aktuell beispielweise die Go Version 1.21.7 installiert habe, dürfte der
Compiler die Anwendung nicht kompilieren, da die go.mod
eine neuere Go
Versionsangabe enthält als tatsächlich installiert.
Der Compiler sollte seine Arbeit eintsellen und mich darauf hinweisen, dass hier wohl eine Inkompatibilität besteht. Das klappt allerdings. Die Anwendung wird kompiliert:
$ go run cmd/main.go
go: downloading go1.22.0 (linux/amd64)
go: updates to go.mod needed; to update it:
go mod tidy
In der obigen Ausgabe sieht man, dass eine neue Toolchain heruntergeladen wird. Das liegt an einem Feature der Go Version 1.21. In dieser Version wurden die Go Auslieferung unterteilt in:
Standardmäßig wird beim Aufruf des go Kommandos in mitgelieferte Toolchain,
bestehende aus Compiler, Assembler und anderen Tools, verwendet. Allerdings
lässt sich mit der Umgebungsvariablen GOTOOLCHAIN oder mit einem Eintrag in der
go.mod
-Datei die zu verwendende Version einer Toolchain angeben.
Die Go-Umgebung lietet nun die Möglichkeit eine alternative Toolchain
herunterzuladen und zu verwenden. Dieses Feature ist standardmäßig an und kann
ebenfalls über die Umgebungsvariable GOTOOLCHAIN
gesteuert werden. Mit dem
Standardwert auto
wird definiert, dass automatisch eine passende Toolchain
heruntergeladen werden soll. Die Angabe einer konkreten Version führt zum
entsprechendem Download.
go env -w GOTOOLCHAIN=go1.21.3
Innerhalb des Projektes meldet das go version
Kommando dementsprechend (die
go.mod
Datei definiert hier die zu verwendende Toolchain):
$ go version
go version go1.22.0 linux/amd64
Im Pfad liegt immer noch die Version 1.21.7! Das heißt, in einem anderen
Verzeichnis wird go version
wieder 1.21.7 melden. Je nach Kontext bzw.
Projekt, wird eine passende Go-Version verwendet.
Kompatibilität rocks!!
WOW! Ab Version 1.21 ist eigentlich fast kein “richtiges” Update der Go-Version nötig. Auch wenn es ein Kompatibilitätsversprechen in Go gibt, unterstützt die Go Umgebung nicht nur eine Source-Code Kompatibilität sondern auch eine Verhaltens-Kompatibilität. Ein echtes Feature!
04.03.2024
Der Author auf LinkedIn: Kristian Köhler und Mastodon: @kkoehler@mastodontech.de
Der praktische Soforteinstieg für Developer und Softwarearchitekten, die direkt mit Go produktiv werden wollen.
zur Buchseite beim Rheinwerk Verlag Rheinwerk Computing, ISBN 978-3-8362-7559-0 (als PDF, EPUB, MOBI und Papier)
Source Fellows GmbH
Lerchenstraße 31
72762 Reutlingen
Telefon: (0049) 07121 6969 802
E-Mail: info@source-fellows.com