スタイルガイド

proto 定義をどのように構造化するのが最適かについての指示を提供します。

このドキュメントは、.proto ファイルのスタイルガイドを提供します。これらの規則に従うことで、プロトコルバッファメッセージ定義とそれに対応するクラスが統一され、読みやすくなります。

標準ファイル形式

  • 行の長さを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つ目のアンダースコアではない)が続く必要があります。

このルールの動機は、各 protobuf 言語実装が識別子をローカル言語スタイルに変換する可能性があることです。.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;
}

// Won't compile - `SET` enum name will clash
// with the one defined in `CollectionType` enum.
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);
}

避けるべきこと

必須フィールド

必須フィールドは、ワイヤバイトを解析する際に特定のフィールドが設定されていることを強制し、そうでなければメッセージの解析を拒否する方法です。この必須の不変性は、通常、メモリ内で構築されたメッセージには強制されません。必須フィールドは proto3 で削除されました。エディション2023に移行された Proto2 の required フィールドは、LEGACY_REQUIRED に設定された field_presence 機能セットを使用して対応できます。

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

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

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

グループ

グループは、ネストされたメッセージの代替構文とワイヤー形式です。グループは proto2 で非推奨と見なされ、proto3 から削除され、エディション2023では区切り表現に変換されます。グループ構文の代わりに、ネストされたメッセージ定義とその型のフィールドを使用できます。ワイヤー互換性のためにmessage_encoding機能を使用してください。

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