Por qué es obligatorio y opcional se elimina en Protocol Buffers 3

216

Recientemente estoy usando gRPCcon proto3, y me di cuenta de eso requiredy optionalse ha eliminado en una nueva sintaxis.

¿Alguien podría explicar amablemente por qué se eliminan los requisitos / opcionales en proto3? Este tipo de restricciones simplemente parecen necesarias para hacer robusta la definición.

sintaxis proto2:

message SearchRequest {
  required string query = 1;
  optional int32 page_number = 2;
  optional int32 result_per_page = 3;
}

sintaxis proto3:

syntax = "proto3";
message SearchRequest {
  string query = 1;
  int32 page_number = 2;
  int32 result_per_page = 3;
}
yjzhang
fuente

Respuestas:

393

La utilidad de requiredha estado en el centro de muchos debates y guerras de fuego. Grandes campamentos han existido en ambos lados. A un campamento le gustaba garantizar que un valor estuviera presente y estaba dispuesto a vivir con sus limitaciones, pero el otro campamento se sentía requiredpeligroso o inútil, ya que no se puede agregar ni eliminar con seguridad.

Permítanme explicar más del razonamiento por el que los requiredcampos deben usarse con moderación. Si ya está utilizando un protocolo, no puede agregar un campo obligatorio porque las aplicaciones antiguas no proporcionarán ese campo y las aplicaciones en general no manejan bien el error. Puede asegurarse de que todas las aplicaciones antiguas se actualicen primero, pero puede ser fácil cometer un error y no ayuda si almacena los protos en cualquier almacén de datos (incluso de corta duración, como memcached). El mismo tipo de situación se aplica al eliminar un campo requerido.

Muchos campos obligatorios fueron "obviamente" requeridos hasta que ... no lo fueron. Digamos que tiene un idcampo para un Getmétodo. Eso es obviamente requerido. Excepto, más tarde puede que necesite cambiar idde int a string, o int32 a int64. Eso requiere agregar un nuevo muchBetterIdcampo, y ahora le queda el idcampo antiguo que debe especificarse, pero finalmente se ignora por completo.

Cuando se combinan esos dos problemas, la cantidad de requiredcampos beneficiosos se vuelve limitada y los campamentos discuten sobre si todavía tiene valor. Los oponentes de requiredno estaban necesariamente en contra de la idea, sino de su forma actual. Algunos sugirieron desarrollar una biblioteca de validación más expresiva que pudiera verificarrequired junto con algo más avanzado como name.length > 10, al tiempo que se aseguraba de tener un mejor modelo de falla.

Proto3 en general parece favorecer la simplicidad, y la requiredeliminación es más simple. Pero quizás sea más convincente, la eliminación requiredtenía sentido para proto3 cuando se combina con otras características, como la eliminación de la presencia de campo para primitivas y la eliminación de valores predeterminados primordiales.

No soy un desarrollador de protobuf y no tengo ninguna autoridad en el tema, pero todavía espero que la explicación sea útil.

Eric Anderson
fuente
23
Sí. Vea también esta explicación extendida de cosas que pueden salir terriblemente mal con los campos obligatorios: capnproto.org/…
Kenton Varda
9
Opcional no se elimina; todo es opcional en proto3. Pero sí, la visibilidad de campo (has_field) se ha eliminado para las primitivas . Si necesita visibilidad de campo, use wrappers.proto que tiene mensajes como StringValue. Como son mensajes, has_field está disponible. Esto es efectivamente "boxeo" que es común en muchos idiomas.
Eric Anderson el
9
Por el contrario, parece que "opcional" se eliminó en proto3. Todos los campos existen y se completan con un valor predeterminado. No tiene forma de saber si el campo primitivo fue completado por el usuario, o por defecto. Los campos de mensaje, que son básicamente punteros, son opcionales, ya que pueden tener un valor nulo.
Vagabundo
15
Siento que protobuf es un lenguaje diseñado expresamente para iniciar las guerras de llamas
Randy L
55
Parece que la mayoría de la gente no quiere versionar sus API. Es más fácil para ellos hacer que todo sea opcional para la "compatibilidad con versiones anteriores".
Holoceo
42

Puede encontrar la explicación en esta edición de Github de protobuf :

Eliminamos los campos obligatorios en proto3 porque los campos obligatorios generalmente se consideran dañinos y violan la semántica de compatibilidad de protobuf. La idea de usar protobuf es que le permite agregar / eliminar campos de la definición de su protocolo sin dejar de ser totalmente compatible con versiones anteriores o anteriores. Sin embargo, los campos obligatorios rompen esto. Nunca puede agregar con seguridad un campo requerido a una definición .proto, ni puede eliminar con seguridad un campo requerido existente porque ambas acciones rompen la compatibilidad del cable. Por ejemplo, si agrega un campo obligatorio a una definición .proto, los archivos binarios creados con la nueva definición no podrán analizar los datos serializados utilizando la definición anterior porque el campo obligatorio no está presente en los datos antiguos. En un sistema complejo donde. las definiciones de protocolo se comparten ampliamente en muchos componentes diferentes del sistema, agregar / eliminar campos requeridos podría fácilmente derribar múltiples partes del sistema. Hemos visto problemas de producción causados ​​por esto varias veces y está prácticamente prohibido en todas partes dentro de Google para que cualquiera pueda agregar / eliminar campos obligatorios. Por esta razón, eliminamos completamente los campos obligatorios en proto3.

Después de eliminar "obligatorio", "opcional" es redundante, por lo que también eliminamos "opcional".

maiyang
fuente
66
No lo entiendo; ¿Cuál es la diferencia entre dejar caer un mensaje después de la deserialización y en la deserialización? el cliente anterior lo descartará, ya que no contiene un campo que sea necesario (por ejemplo, id).
Shmuel H.
66
Me inclino a estar de acuerdo con @ShmuelH. los campos obligatorios serán parte de una API de una forma u otra. Bueno, eso es compatible automáticamente a través de la sintaxis dada a ambas partes, u oculta en el backend, todavía está allí. También podría hacerlo visible en la definición de API
Cruncher
77
Estoy totalmente de acuerdo con @ShmuelH. los campos son obligatorios en una API de una forma u otra y es útil para el cliente saber esto. Esto me hace pensar que todavía no hemos obtenido el control de versiones correcto.
patrickbarker
66
Otro voto para @ShmuelH. Si cambia su API de una manera incompatible con versiones anteriores (agregando un campo requerido), ¿entonces seguramente quiere que su analizador lo detecte? ¡Versión de tus API! Incluso puede hacerlo completamente en Protobuf si lo desea, usando oneof { MessageV1, MessageV2, etc. }.
Timmmm
1
No podía justificar tener campos obligatorios inicialmente. Y agregar un campo requerido es un cambio incompatible y, por lo general, debe manejarse mediante el cambio de versión del protocolo (es decir, un nuevo tipo de mensaje).
kan