スタイルガイド

proto 定義を構造化するための最良の方法に関する指針を提供します。

このドキュメントでは、.proto ファイルのスタイルガイドを提供します。これらの規約に従うことで、protocol buffer メッセージ定義とそれに対応するクラスの一貫性を保ち、読みやすくすることができます。

標準ファイルフォーマット

  • 行の長さを 80 文字に保ちます。
  • インデントには 2 つのスペースを使用します。
  • 文字列にはダブルクォートの使用を推奨します。

ファイル構造

ファイル名は lower_snake_case.proto とする必要があります。

すべてのファイルは以下の順序で記述する必要があります。

  1. ライセンスヘッダー (該当する場合)
  2. ファイルの概要
  3. 構文
  4. パッケージ
  5. インポート (ソート済み)
  6. ファイルオプション
  7. その他すべて

識別子の命名スタイル

Protobuf 識別子では、以下のいずれかの命名スタイルを使用します。

  1. TitleCase
    • 大文字、小文字、および数字を含みます
    • 最初の文字は大文字です
    • 各単語の最初の文字は大文字になります
  2. lower_snake_case
    • 小文字、アンダースコア、および数字を含みます
    • 単語は単一のアンダースコアで区切られます
  3. UPPER_SNAKE_CASE
    • 大文字、アンダースコア、および数字を含みます
    • 単語は単一のアンダースコアで区切られます
  4. camelCase
    • 大文字、小文字、および数字を含みます
    • 最初の文字は小文字です
    • 後続の各単語の最初の文字は大文字になります
    • 注: 以下のスタイルガイドでは、.proto ファイル内の識別子に camelCase は使用しません。用語をここで明確にしているのは、一部の言語の生成コードが識別子をこのスタイルに変換する可能性があるためです。

すべての場合において、略語は単一の単語として扱います。GetDNSRequest ではなく GetDnsRequestd_n_s_request ではなく dns_request を使用してください。

識別子内のアンダースコア

名前の最初または最後の文字としてアンダースコアを使用しないでください。アンダースコアの後には、常に文字 (数字や別のアンダースコアではない) を続ける必要があります。

この規則の理由は、各 protobuf 言語実装が識別子をローカル言語スタイルに変換する可能性があるためです。.proto ファイル内の song_id という名前は、言語によっては SongIdsongId、または song_id として大文字化されたフィールドのアクセサを持つ可能性があります。

文字の前にのみアンダースコアを使用することで、あるスタイルでは名前が異なる可能性があり、別のスタイルに変換された後に衝突する状況を回避できます。

たとえば、DNS2DNS_2 はどちらも TitleCase として Dns2 に変換されます。これらの名前のいずれかを許可すると、生成されたコードが元の UPPER_SNAKE_CASE スタイルを保持する一部の言語でのみメッセージが使用され、広く普及し、その後、名前が TitleCase に変換される言語で後で使用されて衝突するという苦痛な状況につながる可能性があります。

このスタイル規則を適用すると、XYZ_2 ではなく XYZ2 または XYZ_V2 を使用する必要があることを意味します。

パッケージ

パッケージ名には、ドット区切りの lower_snake_case 名を使用します。

複数語のパッケージ名は、lower_snake_case または dot.delimited にすることができます (ドット区切りのパッケージ名は、ほとんどの言語でネストされたパッケージ/名前空間として出力されます)。

パッケージ名は、プロジェクト名に基づいて短く、かつ一意の名前になるように試みる必要があります。パッケージ名は Java パッケージ (com.x.y) にすべきではありません。代わりに、x.y をパッケージとして使用し、必要に応じて java_package オプションを使用します。

メッセージ名

メッセージ名には TitleCase を使用します。

message SongRequest {
}

フィールド名

フィールド名には snake_case を使用します (拡張機能を含む)。

repeated フィールドには複数形名を使用します。

string song_name = 1;
repeated Song songs = 2;

Oneof 名

oneof 名には lower_snake_case を使用します。

oneof song_id {
  string song_human_readable_id = 1;
  int64 song_machine_id = 2;
}

Enum

enum 型名には TitleCase を使用します。

enum 値名には UPPER_SNAKE_CASE を使用します。

enum FooBar {
  FOO_BAR_UNSPECIFIED = 0;
  FOO_BAR_FIRST_VALUE = 1;
  FOO_BAR_SECOND_VALUE = 2;
}

最初にリストされる値は、ゼロ値の enum であり、_UNSPECIFIED または _UNKNOWN のいずれかのサフィックスを持つ必要があります。この値は、不明/デフォルト値として使用でき、明示的に設定されることが期待されるセマンティック値とは区別される必要があります。指定されていない enum 値の詳細については、Proto ベストプラクティスのページを参照してください。

Enum 値のプレフィックス

Enum 値は、意味的にはそれらを含む enum 名によってスコープされないと見なされるため、2 つの兄弟 enum で同じ名前を使用することは許可されていません。たとえば、次の例は、2 つの enum で定義された SET 値が同じスコープ内にあると見なされるため、protoc によって拒否されます。

enum CollectionType {
  COLLECTION_TYPE_UNSPECIFIED = 0;
  SET = 1;
  MAP = 2;
  ARRAY = 3;
}

enum TennisVictoryType {
  TENNIS_VICTORY_TYPE_UNSPECIFIED = 0;
  GAME = 1;
  SET = 2;
  MATCH = 3;
}

名前の衝突は、enum がファイルのトップレベルで定義されている場合 (メッセージ定義内にネストされていない場合) にリスクが高くなります。その場合、兄弟には同じパッケージを設定する他のファイルで定義された enum が含まれ、protoc はコード生成時に衝突が発生したことを検出できない可能性があります。

これらのリスクを回避するために、次のいずれかを強く推奨します。

  • すべての値に enum 名をプレフィックスとして付与します (UPPER_SNAKE_CASE に変換)。
  • enum を含むメッセージ内にネストします。

どちらのオプションでも衝突のリスクを軽減するのに十分ですが、問題を軽減するためだけにメッセージを作成するよりも、プレフィックス付きの値を持つトップレベルの enum を優先します。一部の言語では、enum が「struct」型内で定義されることをサポートしていないため、プレフィックス付きの値を優先することで、バインディング言語間で一貫したアプローチが保証されます。

サービス

サービス名とメソッド名には TitleCase を使用します。

service FooService {
  rpc GetSomething(GetSomethingRequest) returns (GetSomethingResponse);
  rpc ListSomething(ListSomethingRequest) returns (ListSomethingResponse);
}

サービス関連のガイダンスの詳細については、API ベストプラクティスのトピックの メソッドごとに一意の Proto を作成する および トップレベルのリクエストまたはレスポンス Proto にプリミティブ型を含めないでください、および Proto ベストプラクティスの メッセージを個別のファイルで定義する を参照してください。

避けるべきこと

必須フィールド

必須フィールドは、ワイヤバイトを解析するときに特定のフィールドを必ず設定する必要があるように強制し、そうでない場合はメッセージの解析を拒否する方法です。必須の不変条件は、通常、メモリ内で構築されたメッセージには適用されません。必須フィールドは proto3 で削除されました。

スキーマレベルで必須フィールドを強制することは直感的には望ましいですが、protobuf の主要な設計目標の 1 つは、長期的なスキーマの進化をサポートすることです。特定のフィールドが今日どれほど明らかに必須であるように見えても、そのフィールドを設定する必要がなくなる可能性のある将来があります (例: int64 user_id は将来 UserId user_id に移行する必要があるかもしれません)。

特に、処理する必要のないメッセージを転送する可能性のあるミドルウェアサーバーの場合、required のセマンティクスは、長期的な進化の目標にとって非常に有害であることが証明されており、現在では強く推奨されていません。

必須フィールドは強く非推奨 を参照してください。

グループ

グループは、ネストされたメッセージの代替構文およびワイヤ形式です。グループは proto2 では非推奨と見なされ、proto3 から削除されました。グループ構文を使用する代わりに、ネストされたメッセージ定義とその型のフィールドを使用する必要があります。

グループ を参照してください。