Style Guide
Dieses Dokument bietet einen Styleguide für .proto-Dateien. Durch die Befolgung dieser Konventionen machen Sie Ihre Protocol Buffer-Nachrichtendefinitionen und ihre entsprechenden Klassen konsistent und leicht lesbar.
Die Durchsetzung der folgenden Stilrichtlinien wird über enforce_naming_style gesteuert.
Standard-Datei-Formatierung
- Halten Sie die Zeilenlänge auf 80 Zeichen.
- Verwenden Sie einen Einzug von 2 Leerzeichen.
- Bevorzugen Sie die Verwendung von doppelten Anführungszeichen für Strings.
Dateistruktur
Dateien sollten lower_snake_case.proto genannt werden.
Alle Dateien sollten wie folgt geordnet sein
- Lizenz-Header (falls zutreffend)
- Datei-Übersicht
- Syntax
- Paket
- Imports (sortiert)
- Datei-Optionen
- Alles andere
Namenskonventionen für Bezeichner
Protobuf-Bezeichner verwenden eine der folgenden Namenskonventionen
- TitleCase
- Enthält Großbuchstaben, Kleinbuchstaben und Zahlen
- Das erste Zeichen ist ein Großbuchstabe
- Der erste Buchstabe jedes Wortes ist großgeschrieben
- lower_snake_case
- Enthält Kleinbuchstaben, Unterstriche und Zahlen
- Wörter sind durch einen einzelnen Unterstrich getrennt
- UPPER_SNAKE_CASE
- Enthält Großbuchstaben, Unterstriche und Zahlen
- Wörter sind durch einen einzelnen Unterstrich getrennt
- camelCase
- Enthält Großbuchstaben, Kleinbuchstaben und Zahlen
- Das erste Zeichen ist ein Kleinbuchstabe
- Der erste Buchstabe jedes nachfolgenden Wortes ist großgeschrieben
- Hinweis: Der folgende Styleguide verwendet kein camelCase für Bezeichner in .proto-Dateien; die Terminologie wird hier nur klargestellt, da einige sprachspezifisch generierter Code Bezeichner in diesen Stil umwandeln kann.
Behandeln Sie Abkürzungen in allen Fällen so, als wären sie einzelne Wörter: verwenden Sie GetDnsRequest anstelle von GetDNSRequest, dns_request anstelle von d_n_s_request.
Unterstriche in Bezeichnern
Verwenden Sie keine Unterstriche als Anfangs- oder Endzeichen eines Namens. Jeder Unterstrich sollte immer von einem Buchstaben gefolgt werden (nicht von einer Zahl oder einem zweiten Unterstrich).
Der Grund für diese Regel ist, dass jede Protobuf-Sprachimplementierung Bezeichner in den lokalen Sprachstil umwandeln kann: Ein Name wie song_id in einer .proto-Datei kann später Zugriffsfunktionen für das Feld haben, die je nach Sprache als SongId, songId oder song_id großgeschrieben werden.
Durch die ausschließliche Verwendung von Unterstrichen vor Buchstaben werden Situationen vermieden, in denen Namen in einem Stil unterschiedlich sind, aber nach der Umwandlung in einen der anderen Stile kollidieren.
Beispielsweise würden sowohl DNS2 als auch DNS_2 beide als Dns2 in TitleCase umgewandelt werden. Die Zulassung eines dieser Namen kann zu problematischen Situationen führen, wenn eine Nachricht nur in einigen Sprachen verwendet wird, in denen der generierte Code den ursprünglichen UPPER_SNAKE_CASE-Stil beibehält, weit verbreitet wird und dann später in einer Sprache verwendet wird, in der Namen nach TitleCase umgewandelt werden, wo sie kollidieren.
Bei Anwendung dieser Stilregel sollten Sie XYZ2 oder XYZ_V2 anstelle von XYZ_2 oder XYZ_2V verwenden.
Pakete (Packages)
Verwenden Sie punktgetrennte lower_snake_case-Namen als Paketnamen.
Mehrwortige Paketnamen können lower_snake_case oder punkt.getrennt sein (punktgetrennte Paketnamen werden in den meisten Sprachen als verschachtelte Pakete/Namespaces ausgegeben).
Paketnamen sollten versuchen, ein kurzer, aber eindeutiger Name zu sein, der auf dem Projektnamen basiert. Paketnamen sollten keine Java-Pakete sein (com.x.y); verwenden Sie stattdessen x.y als Paket und verwenden Sie bei Bedarf die Option java_package.
Nachrichten-Namen
Verwenden Sie TitleCase für Nachrichtennamen.
message SongRequest {
}
Feldnamen
Verwenden Sie snake_case für Feldnamen, einschließlich Erweiterungen.
Verwenden Sie Pluralformen für wiederholte Felder.
string song_name = 1;
repeated Song songs = 2;
Oneof-Namen
Verwenden Sie lower_snake_case für Oneof-Namen.
oneof song_id {
string song_human_readable_id = 1;
int64 song_machine_id = 2;
}
Enums
Verwenden Sie TitleCase für Enum-Typnamen.
Verwenden Sie UPPER_SNAKE_CASE für Enum-Wertnamen.
enum FooBar {
FOO_BAR_UNSPECIFIED = 0;
FOO_BAR_FIRST_VALUE = 1;
FOO_BAR_SECOND_VALUE = 2;
}
Der erste aufgeführte Wert sollte ein Null-Wert-Enum sein und die Endung _UNSPECIFIED oder _UNKNOWN haben. Dieser Wert kann als unbekannter/Standardwert verwendet werden und sollte von allen semantischen Werten, die explizit gesetzt werden sollen, abweichen. Weitere Informationen zum nicht spezifizierten Enum-Wert finden Sie auf der Seite Proto Best Practices.
Enum-Wert-Präfixierung
Enum-Werte werden semantisch so betrachtet, dass sie nicht durch ihren enthaltenden Enumnamen eingeschränkt sind, sodass derselbe Name in zwei Geschwister-Enums nicht zulässig ist. Beispielsweise würde das Folgende von protoc abgelehnt, da der in den beiden Enums definierte SET-Wert als im selben Gültigkeitsbereich befindlich betrachtet wird
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;
}
Namenskollisionen stellen ein hohes Risiko dar, wenn Enums auf der obersten Ebene einer Datei definiert werden (nicht verschachtelt in einer Nachrichtendefinition); in diesem Fall umfassen Geschwister-Enums, die in anderen Dateien definiert sind und denselben Paketnamen haben, wo protoc die Kollision zur Zeit der Codegenerierung möglicherweise nicht erkennen kann.
Um diese Risiken zu vermeiden, wird dringend empfohlen, Folgendes zu tun
- Präfixieren Sie jeden Wert mit dem Enumnamen (konvertiert in UPPER_SNAKE_CASE)
- Verschachteln Sie das Enum in einer enthaltenden Nachricht
Jede Option reicht aus, um Kollisionsrisiken zu mindern, aber bevorzugen Sie Top-Level-Enums mit präfixierten Werten gegenüber der Erstellung einer Nachricht nur zur Minderung des Problems. Da einige Sprachen Enums, die innerhalb eines „Struktur“-Typs definiert sind, nicht unterstützen, stellt die Bevorzugung von präfixierten Werten einen konsistenten Ansatz über Bindungssprachen hinweg sicher.
Services
Verwenden Sie TitleCase für Service- und Methodennamen.
service FooService {
rpc GetSomething(GetSomethingRequest) returns (GetSomethingResponse);
rpc ListSomething(ListSomethingRequest) returns (ListSomethingResponse);
}
Was Sie vermeiden sollten
Erforderliche Felder
Erforderliche Felder sind eine Möglichkeit, sicherzustellen, dass ein bestimmtes Feld beim Parsen von Wire-Bytes gesetzt sein muss und andernfalls das Parsen der Nachricht verweigert wird. Die erforderliche Invariante wird im Allgemeinen bei in Speicher erstellten Nachrichten nicht erzwungen. Erforderliche Felder wurden in proto3 entfernt. Proto2 required-Felder, die zu Edition 2023 migriert wurden, können die Funktion field_presence auf LEGACY_REQUIRED setzen, um dies zu berücksichtigen.
Obwohl die Durchsetzung erforderlicher Felder auf Schemaebene wünschenswert ist, ist eines der Hauptziele des Designs von Protobuf die Unterstützung der langfristigen Schema-Evolution. Egal wie offensichtlich erforderlich ein bestimmtes Feld heute zu sein scheint, es gibt eine plausible Zukunft, in der das Feld nicht mehr gesetzt werden sollte (z.B. muss ein int64 user_id in Zukunft möglicherweise zu einem UserId user_id migriert werden).
Insbesondere bei Middleware-Servern, die Nachrichten weiterleiten, die sie nicht wirklich verarbeiten müssen, hat sich die Semantik von required als zu schädlich für diese langfristigen Evolutionsziele erwiesen, und ist daher jetzt sehr stark abgeraten.
Siehe Required ist stark veraltet.
Gruppen
Groups sind eine alternative Syntax und ein alternativer Wire-Format für verschachtelte Nachrichten. Groups gelten in proto2 als veraltet, wurden aus proto3 entfernt und werden in Edition 2023 in eine abgegrenzte Darstellung umgewandelt. Sie können eine verschachtelte Nachrichtendefinition und ein Feld dieses Typs anstelle der Group-Syntax verwenden, wobei die Funktion message_encoding für Wire-Kompatibilität verwendet wird.
Siehe groups.