Go Opaque API-Migration

Beschreibt die automatisierte Migration zur Opaque API.

Die Opaque API ist die neueste Version der Protocol Buffers-Implementierung für die Go-Programmiersprache. Die alte Version wird nun Open Struct API genannt. Informationen zur Einführung finden Sie im Blogbeitrag Go Protobuf: Releasing the Opaque API.

Die Migration zur Opaque API erfolgt inkrementell, pro Proto-Nachricht oder pro .proto-Datei, indem das api_level-Feature auf einen seiner möglichen Werte gesetzt wird

  • API_OPEN wählt die Open Struct API. Diese wurde in Edition 2023 zurückportiert, daher unterstützen ältere Versionen des Go-Plugins diese möglicherweise nicht.
  • API_HYBRID ist ein Schritt zwischen Open und Opaque: Die Hybrid-API enthält auch Accessor-Methoden (damit Sie Ihren Code aktualisieren können), exportiert aber weiterhin die Strukturfelder wie zuvor. Es gibt keinen Leistungsunterschied; diese API-Ebene dient nur der Migration.
  • API_OPAQUE wählt die Opaque API; dies ist der Standard für Edition 2024 und neuer.

Um den Standard für eine bestimmte .proto-Datei zu überschreiben, setzen Sie das api_level-Feature

edition = "2024";

package log;

import "google/protobuf/go_features.proto";
option features.(pb.go).api_level = API_OPEN;

message LogEntry {  }

Bevor Sie das api_level für vorhandene Dateien auf API_OPAQUE ändern können, müssen alle vorhandenen Verwendungen des generierten Proto-Codes aktualisiert werden. Das Tool open2opaque hilft dabei.

Zu Ihrer Bequemlichkeit können Sie auch das Standard-API-Level mit einem protoc-Kommandozeilenflag überschreiben:

protoc […] --go_opt=default_api_level=API_OPEN

Um das Standard-API-Level für eine bestimmte Datei (anstatt für alle Dateien) zu überschreiben, verwenden Sie das Mapping-Flag apilevelM (ähnlich wie das M-Flag für Importpfade):

protoc […] --go_opt=apilevelMhello.proto=API_OPEN

Automatisierte Migration

Wir versuchen, die Migration bestehender Projekte zur Opaque API für Sie so einfach wie möglich zu gestalten: Unser Tool open2opaque erledigt den Großteil der Arbeit!

Um das Migrationstool zu installieren, verwenden Sie

go install google.golang.org/open2opaque@latest
go install golang.org/x/tools/cmd/goimports@latest

Projektvorbereitung

Stellen Sie sicher, dass Ihre Build-Umgebung und Ihr Projekt ausreichend aktuelle Versionen von Protocol Buffers und Go Protobuf verwenden

  1. Aktualisieren Sie den protobuf-Compiler (protoc) von der protobuf-Release-Seite auf Version 29.0 oder neuer.

  2. Aktualisieren Sie das protobuf-Compiler-Go-Plugin (protoc-gen-go) auf Version 1.36.0 oder neuer

    go install google.golang.org/protobuf/cmd/protoc-gen-go@latest
    
  3. Aktualisieren Sie in jedem Projekt die go.mod-Datei, um das protobuf-Modul in Version 1.36.0 oder neuer zu verwenden

    go get google.golang.org/protobuf@latest
    

Schritt 1. Wechseln Sie zur Hybrid-API

Verwenden Sie das Tool open2opaque, um Ihre .proto-Dateien auf die Hybrid-API umzustellen

open2opaque setapi -api HYBRID $(find . -name "*.proto")

Kompilieren Sie dann Ihre Protocol Buffers erneut neu.

Ihr bestehender Code wird weiterhin kompiliert. Die Hybrid-API ist ein Schritt zwischen der Open- und der Opaque-API, der die neuen Accessor-Methoden hinzufügt, aber die Strukturfelder sichtbar lässt.

Schritt 2. open2opaque rewrite

Um Ihren Go-Code für die Verwendung der Opaque API umzuschreiben, führen Sie den Befehl open2opaque rewrite aus

open2opaque rewrite -levels=red github.com/robustirc/robustirc/...

Sie können ein oder mehrere Pakete oder Muster angeben.

Wenn Sie beispielsweise Code wie diesen hatten

logEntry := &logpb.LogEntry{}
if req.IPAddress != nil {
    logEntry.IPAddress = redactIP(req.IPAddress)
}
logEntry.BackendServer = proto.String(host)

Das Tool würde ihn umschreiben, um Accessoren zu verwenden

logEntry := &logpb.LogEntry{}
if req.HasIPAddress() {
    logEntry.SetIPAddress(redactIP(req.GetIPAddress()))
}
logEntry.SetBackendServer(host)

Ein weiteres gängiges Beispiel ist die Initialisierung einer protobuf-Nachricht mit einem Strukturliteral

return &logpb.LogEntry{
    BackendServer: proto.String(host),
}

In der Opaque API ist das Äquivalent die Verwendung eines Builders

return logpb.LogEntry_builder{
    BackendServer: proto.String(host),
}.Build()

Das Tool klassifiziert seine verfügbaren Umschreibungen in verschiedene Stufen. Das Argument -levels=red aktiviert alle Umschreibungen, einschließlich derjenigen, die eine menschliche Überprüfung erfordern. Die folgenden Stufen sind verfügbar

  • grün: Sichere Umschreibungen (hohe Zuverlässigkeit). Enthält die meisten Änderungen, die das Tool vornimmt. Diese Änderungen erfordern keine genaue Betrachtung und könnten sogar automatisiert ohne menschliche Aufsicht eingereicht werden.
  • gelb: (angemessene Zuverlässigkeit) Diese Umschreibungen erfordern eine menschliche Überprüfung. Sie sollten korrekt sein, aber bitte überprüfen Sie sie.
  • rot: Potenziell gefährliche Umschreibungen, die seltene und komplizierte Muster ändern. Diese erfordern eine sorgfältige menschliche Überprüfung. Wenn eine bestehende Funktion beispielsweise einen *string-Parameter nimmt, funktioniert die übliche Korrektur durch die Verwendung von proto.String(msg.GetFoo()) nicht, wenn die Funktion beabsichtigte, den Feldwert durch Schreiben auf den Zeiger zu ändern (*foo = "value").

Viele Programme können vollständig mit nur grünen Änderungen migriert werden. Bevor Sie eine Proto-Nachricht oder -Datei in die Opaque API migrieren können, müssen Sie alle Umschreibungen aller Stufen abschließen, an diesem Punkt bleibt kein direkter Strukturzugriff mehr in Ihrem Code.

Schritt 3. Migrieren und Überprüfen

Um die Migration abzuschließen, verwenden Sie das Tool open2opaque, um Ihre .proto-Dateien auf die Opaque API umzustellen

open2opaque setapi -api OPAQUE $(find . -name "*.proto")

Nun wird jeglicher verbleibender Code, der noch nicht in die Opaque API umgeschrieben wurde, nicht mehr kompiliert.

Führen Sie Ihre Unit-Tests, Integrationstests und andere Verifizierungsschritte aus, falls vorhanden.

Fragen? Probleme?

Überprüfen Sie zunächst die Opaque API FAQ. Wenn diese Ihre Frage nicht beantwortet oder Ihr Problem nicht löst, lesen Sie Wo kann ich Fragen stellen oder Probleme melden?