スタイルガイド

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 を使用してください。

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

名前にアンダースコアを最初または最後の文字として使用しないでください。アンダースコアの後には必ず文字が続きます(数字や2つ目のアンダースコアは不可)。

この規則の動機は、各 Protocol Buffer 言語実装が識別子をローカル言語スタイルに変換する可能性があるためです。.proto ファイル内の song_id という名前は、言語に応じて SongIdsongId、または song_id としてアクセスされるフィールドになる可能性があります。

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

たとえば、DNS2DNS_2 はどちらも TitleCase で Dns2 に変換されます。これらの名前のいずれかを許可すると、メッセージが生成コードが元の UPPER_SNAKE_CASE スタイルを保持する一部の言語でのみ使用され、広く確立された後、名前が TitleCase に変換されて衝突する言語で後から使用される場合に、問題が生じる可能性があります。

このスタイル規則を適用する場合、XYZ_2 または XYZ_2V ではなく、XYZ2 または XYZ_V2 を使用する必要があります。

パッケージ

パッケージ名にはドットで区切られた lower_snake_case の名前を使用します。

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

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

メッセージ名

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

message SongRequest {
}

フィールド名

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

繰り返しフィールドには複数形を使用します。

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 を定義することをサポートしていないため、プレフィックス付きの値を優先することで、バインディング言語全体で一貫したアプローチが保証されます。

サービス

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

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

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

避けるべきこと

必須フィールド

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

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

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

Required は強く非推奨ですを参照してください。

グループ

グループは、ネストされたメッセージの代替構文とワイヤーフォーマットです。グループは proto2 で非推奨とされ、proto3 から削除されました。グループ構文を使用する代わりに、ネストされたメッセージ定義とその型のフィールドを使用すべきです。

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