Protocol Buffers 入門:.protoファイルの設計
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