Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

  • Don’t use the required the field. The required field raises a decoding error if the field is not present in the message, which restricts the backward and forward compatibility of a proto message. For cockroach specifically, sending messages between two crdb nodes with different binaries becomes treacherous.

  • Use the gogoproto.nullable option so the compiled field type is the type itself instead of a pointer. We use this option because we want our generated proto structs to look and feel like regular go structs-- specifically, we follow the convention that the absence of the value is represented as the 0 value of the type, instead of a null pointer. Note that by default go primitive types are compiled to the type itself. There are two exceptions to this recommendation:

    • If you really need to distinguish between the zero value vs absent, then don’t set this option. Further, if you want a pointer to a primitive type, set gogoproto.nullable=false.

    • If the type of the field is very large, i.e. another message type with lots and lots of fields, and if we'll be passing instances of the containing type around often. Then the one time alloc and just copying addr to pass it can actually be cheaper. But this too is pretty rare (I imagine it might hold for Descriptor and RequestUnion but not many others).

  • Don’t use the optional field. As described here, it allows the user to distinguish between the zero value and if the field is absent. If you need this, work with gogoproto.nullable invocation so the compiled field is nullable.

  • Avoid types.Any and json types like the plague. They are very hard to decode while inspecting them in a debug zip.

Gotchas

  • For protobufs on performance critical paths, beware that empty fields can have non zero space overhead when marshalled. To ensure these fields are truly empty in the encoded message, use Radu’s fancy omitEmpty field.

...