Skip to content

Protobuf code style

Alexander Yevsyukov edited this page Jul 11, 2023 · 3 revisions

Table of contents


General Rules

  • 4 spaces (instead of 2) for indentation — we want it less dense and inline with Java indentation.
  • 100 characters right margin;

File header

A proto file header should follow the layout below:

//
// Copyright header goes here...
//
syntax = "proto3";

option (type_url_prefix) = "type.spine3.org";
option java_package = "org.spine3.[package]";
option java_outer_classname = "[Outer Class Name]";
option java_multiple_files = true;

import "google/protobuf/timestamp.proto";

import "spine/annotations.proto";

Note that the type_url_prexix option goes immediately before the java_package.

Imports of Google Protobuf types should be grouped together after the section with options. Allow one empty line before this group.

Spine-related imports should follow after an empty line break.

API documentation

If documentation of a type or a field fits into one paragraph, do NOT add an empty line after the paragraph.

// This is now to document a proto type description of which
// fits into one paragraph.
message OneParaExample {

    // Contains important details about the foo.
    string foo = 1;
}

If a field or a message requires two or more paragraphs, the text should end with an empty line.

// Demonstrates how to document API with larger pieces of text.
//
// Such docs may give examples or extend the brief information given in the first paragraph.
//
message TwoParaExample {

   // This field requires more explanation.
   //
   // It could be this, and it could be that. Have an empty line in such a text.
   //
   uint32 bar = 2;
}

Nested types declaration

To improve readability, please declare a nested type right after the field declaration:

message SearchResponse {

  // Field declaration goes first. 
  repeated Result results = 1;

  // Nested type is declared after the field of its type.
  message Result {
      string url = 1;
      string title = 2;
      repeated string snippet = 3;
  }
}

In case there are several nested-typed fields, the nested type itself is declared after the first field occurrence.

Code in Prototobuf documentation and GitHub comments

Please use ` ` quotes (as in Markdown) to mark code names in Protobuf documentation and GitHub comments.

  // This field contains string representation of `AggregateId`.
  string aggregate = 5;

Naming repeated and map fields

Repeated and map fields should be singular.

Repeated and map fields should be named with singular nouns:

   repeated Item item = 3;
   map<string, Value> value = 4;

The generated Java code would then have:

   List<Item> getItemList() { ... }
   Builder addItem(Item item) { ... }
      
   Value getValueOrThrow(String key) { ... }
   Value getValueOrDefault(String key) { ... }
   Builder putValue(String key, Value value) { ... }
   Builder removeValue(String key) { ... }   
   

and other methods that play nicely with singular field names.

NOTE: This rule contradicts with the Google Cloud API Naming Conventions which requires that maps and repeated fields must be named after plural nouns. Knowing this, we still recommend singular because of the following.

The code generated for a repeated or a map field named after a singular noun is closer to real English. For new code and the code related to Domain-Driven Design this is far more important than consistency with the Google Cloud API.

Since the framework isolates the infrastructure aspects (such as cloud environment or storage), the Cloud API is going to be accessed by a minority of developers of a Spine-based project. Most of the developers of such a project won't face the naming inconsistency, while enjoying better pronounced API of their domain.

Clone this wiki locally