Zenn
🙆‍♀️

Protocol Buffers 入門:.protoファイルの設計

2025/03/31に公開

Googleが開発したデータシリアライズフォーマット「Protocol Buffers(protobuf)」は、高速かつ軽量で、さまざまな言語に対応しています。最近勉強しはじめたのでこの記事では、.proto ファイルの基本構造から、実運用に耐える定義の設計・進化方法までを紹介します。
間違いが存在する場合はコメントで教えて頂ければ有り難いです。


1. .proto ファイルの基本構成

.proto ファイルは、以下のような構成で始まります。

syntax = "proto3"; // 文法のバージョン指定(proto2 も可)

package myapp.user; // 名前空間を定義(名前衝突を防ぐ)

option go_package = "github.com/example/myapp/userpb"; // Go言語用のパッケージ指定

message User {
  string name = 1;
  int32 age = 2;
}

syntax は文法バージョン(現在は proto3 が主流)

package は名前空間であり、異なる .proto 間の衝突を回避できます

option go_package はGoコード生成時のパッケージ名を制御するための重要なオプションです


2. フィールドの修飾子(カーディナリティ)

フィールドの繰り返しや省略可能性を表すキーワードには以下のものがあります:

例:

optional string nickname = 3;
repeated string email_addresses = 4;

3. 命名のルールと注意点

.proto におけるフィールド命名には、以下のガイドラインがあります:

  • 一度使ったフィールド名は、本番環境では極力変更しない(互換性の問題)

  • repeated フィールドには 複数形の名前 を使う

  • フィールド名には ハイフン(-)を使わない(例:user_name はOK、user-name はNG)

  • 名前の変更ではなく、deprecated オプションで非推奨にするのが推奨される

例:

int32 age = 2 [deprecated = true]; // 今後使わないフィールド

4. 後方互換性と前方互換性

Protocol Buffers は、以下のように互換性に優れています。

古いコードが新しいメッセージを読むと…

  • 新しいフィールドは無視される(問題なし)

  • 削除されたフィールドはデフォルト値で扱われる

新しいコードが古いメッセージを読むと…

  • 新しいフィールドは存在しないが、自動でデフォルト値が使われる

このため、以下のようなベストプラクティスを守ることで、安全に .proto を更新することが可能:

  • フィールドの番号(タグ番号)は絶対に変更しない

  • 削除より deprecated や reserved を使う

  • 新しいフィールドは未使用の番号で追加する

例(reserved の使用):

message Product {
  reserved 4, 6 to 8;
  reserved "old_field", "legacy_name";
}

Discussion

ログインするとコメントできます