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 の間のステップです。Hybrid API にはアクセサメソッドも含まれています(コードを更新できます)が、struct フィールドは以前と同様にエクスポートされます。パフォーマンスの違いはありません。この 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 コンパイラ (protoc) を protobuf リリース ページ からバージョン 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. Hybrid API に切り替える

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

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

既存のコードは引き続きビルドされます。Hybrid API は、新しいアクセサメソッドを追加しますが、struct フィールドを表示したままにする 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)

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

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

Opaque API では、同等のものは Builder を使用することです。

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

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

  • green: 安全な書き換え (高信頼度)。ツールが行うほとんどの変更が含まれます。これらの変更は詳細な確認を必要とせず、人間の監視なしに自動化によって送信することもできます。
  • yellow: (妥当な信頼度) これらの書き換えには人間によるレビューが必要です。それらは正しいはずですが、レビューしてください。
  • red: 潜在的に危険な書き換え。まれで複雑なパターンを変更します。これらには注意深い人間によるレビューが必要です。たとえば、既存の関数が *string パラメーターを受け取る場合、ポインターに書き込むことによってフィールド値を変更することを目的としている場合 (*foo = "value")、proto.String(msg.GetFoo()) を使用する一般的な修正は機能しません。

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

ステップ 3. 移行と検証

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

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

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

ユニットテスト、統合テスト、およびその他の検証手順(ある場合)を実行します。

質問や issue はありますか?

まず、Opaque API FAQ を確認してください。それでも質問に答えられない場合や問題が解決しない場合は、質問や issue を報告できる場所はどこですか? を参照してください。