Go Opaque API への移行

Opaque API への自動移行について説明します。

Opaque API は、Go プログラミング言語向けの Protocol Buffers 実装の最新バージョンです。以前のバージョンは Open Struct API と呼ばれています。導入については、「Go Protobuf: Releasing the Opaque API」ブログ記事をご覧ください。

Opaque API への移行は、Protobuf Editions の機能 api_level オプションを可能な値のいずれかに設定することにより、proto メッセージごと、または .proto ファイルごとに段階的に行われます。

  • API_OPEN は Open Struct API を選択します。これは2024年12月以前の唯一のAPIでした。
  • API_HYBRID は Open と Opaque の中間のステップです。ハイブリッド API はアクセサーメソッドも含まれるため(コードを更新できます)、以前と同様に構造体フィールドをエクスポートします。パフォーマンスの差はありません。この API レベルは移行に役立つだけです。
  • API_OPAQUE は Opaque API を選択します。

現在のデフォルトは API_OPEN ですが、今後のProtobuf Edition 2024 ではデフォルトが API_OPAQUE に変更されます。

Edition 2024 より前に Opaque API を使用するには、api_level を次のように設定します。

edition = "2023";

package log;

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

message LogEntry {  }

既存ファイルに対して api_levelAPI_OPAQUE に変更する前に、生成された proto コードの既存のすべての使用箇所を更新する必要があります。open2opaque ツールがこれを支援します。

利便性のため、protoc コマンドラインフラグでデフォルトの API レベルをオーバーライドすることもできます。

protoc […] --go_opt=default_api_level=API_OPAQUE

特定のファイル(すべてのファイルではなく)のデフォルト API レベルをオーバーライドするには、apilevelM マッピングフラグ(インポートパスの M フラグ と同様)を使用します。

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

コマンドラインフラグは、proto2 または proto3 構文を使用している .proto ファイルでも機能しますが、.proto ファイル内から API レベルを選択したい場合は、まずそのファイルをエディションに移行する必要があります。

自動移行

既存のプロジェクトを Opaque API に移行する作業を可能な限り簡単にするよう努めています。当社の open2opaque ツールがほとんどの作業を行います!

移行ツールをインストールするには、次を使用します。

go install google.golang.org/open2opaque@latest

プロジェクトの準備

ビルド環境とプロジェクトが十分新しいバージョンの Protocol Buffers および Go Protobuf を使用していることを確認してください。

  1. protobuf リリースページから protobuf コンパイラ (protoc) をバージョン 29.0 以降に更新してください。

  2. protobuf コンパイラ Go プラグイン (protoc-gen-go) をバージョン 1.36.0 以降に更新してください。

    go install google.golang.org/protobuf/cmd/protoc-gen-go@latest
    
  3. 各プロジェクトで、go.mod ファイルを更新して、バージョン 1.36.0 以降の protobuf モジュールを使用するようにしてください。

    go get google.golang.org/protobuf@latest
    

ステップ1. ハイブリッドAPIへの切り替え

open2opaque ツールを使用して、.proto ファイルをハイブリッド API に切り替えます。

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

既存のコードは引き続きビルドされます。ハイブリッド API は、Open API と Opaque API の間のステップであり、新しいアクセサーメソッドを追加しますが、構造体フィールドは引き続き表示されます。

ステップ2. open2opaque rewrite

Go コードを Opaque API を使用するように書き換えるには、open2opaque rewrite コマンドを実行します。

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

1つまたは複数のパッケージまたはパターンを指定できます。

例として、次のようなコードがあった場合:

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

ツールはそれをアクセサーを使用するように書き換えます。

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

もう一つの一般的な例は、構造体リテラルで protobuf メッセージを初期化することです。

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

Opaque API では、同等の機能として Builder を使用します。

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

このツールは、利用可能な書き換えを異なるレベルに分類します。-levels=red 引数は、人間のレビューを必要とするものを含め、すべての書き換えを有効にします。利用可能なレベルは次のとおりです。

  • 緑: 安全な書き換え(高信頼度)。ツールが行うほとんどの変更が含まれます。これらの変更は綿密な確認を必要とせず、人間の監視なしに自動化によってコミットすることも可能です。
  • 黄: (妥当な信頼度)これらの書き換えは人間のレビューが必要です。これらは正しいはずですが、確認をお願いします。
  • 赤: 潜在的に危険な書き換えで、稀で複雑なパターンを変更します。これらは慎重な人間のレビューが必要です。例えば、既存の関数が *string パラメーターを取る場合、関数がポインターに書き込むことでフィールド値を変更しようとしていた場合(*foo = "value")、一般的な修正である proto.String(msg.GetFoo()) の使用は機能しません。

多くのプログラムは緑色の変更のみで完全に移行できます。proto メッセージまたはファイルを Opaque API に移行する前に、すべてのレベルのすべての書き換えを完了する必要があります。その時点では、コード内に直接的な構造体アクセスは残りません。

ステップ3. 移行と検証

移行を完了するには、open2opaque ツールを使用して、.proto ファイルを Opaque API に切り替えます。

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

ここで、まだ Opaque API に書き換えられていない残りのコードはコンパイルされなくなります。

必要に応じて、単体テスト、統合テスト、およびその他の検証手順を実行してください。

質問はありますか?問題がありますか?

まず、Opaque API FAQ を確認してください。それで質問が解決しない場合や問題が解決しない場合は、「どこで質問したり問題を報告できますか?」を参照してください。