Por que o obrigatório e o opcional são removidos nos Buffers de Protocolo 3

214

Estou usando recentemente gRPCcom proto3e notei isso requirede optionalfoi removido na nova sintaxe.

Alguém gentilmente explicaria por que o obrigatório / opcional é removido no proto3? Esse tipo de restrição parece necessário para tornar a definição robusta.

sintaxe proto2:

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

sintaxe proto3:

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

Respostas:

388

A utilidade de requiredtem estado no centro de muitos debates e guerras de chamas. Grandes campos existem em ambos os lados. Um campo gostava de garantir a presença de um valor e estava disposto a viver com suas limitações, mas o outro campo parecia requiredperigoso ou inútil, pois não pode ser adicionado nem removido com segurança.

Deixe-me explicar mais sobre o motivo pelo qual os requiredcampos devem ser usados ​​com moderação. Se você já estiver usando um proto, não poderá adicionar um campo obrigatório, pois os aplicativos antigos não fornecerão esse campo e os aplicativos em geral não lidam bem com a falha. Você pode garantir que todos os aplicativos antigos sejam atualizados primeiro, mas pode ser fácil cometer um erro e não ajuda se você estiver armazenando os protos em qualquer armazenamento de dados (mesmo de curta duração, como o cache de memórias). O mesmo tipo de situação se aplica ao remover um campo obrigatório.

Muitos campos obrigatórios eram "obviamente" necessários até ... não eram. Digamos que você tenha um idcampo para um Getmétodo. Isso é obviamente necessário. Exceto, mais tarde, pode ser necessário alterar idde int para string ou int32 para int64. Isso requer a adição de um novo muchBetterIdcampo e agora você fica com o idcampo antigo que deve ser especificado, mas eventualmente é completamente ignorado.

Quando esses dois problemas são combinados, o número de requiredcampos benéficos se torna limitado e os campos discutem se ele ainda tem valor. Os oponentes de requirednão eram necessariamente contra a idéia, mas sua forma atual. Alguns sugeriram o desenvolvimento de uma biblioteca de validação mais expressiva que pudesse requiredacompanhar algo mais avançado name.length > 10, além de garantir um melhor modelo de falha.

No geral, o Proto3 parece favorecer a simplicidade e a requiredremoção é mais simples. Mas talvez mais convincente, a remoção requiredfizesse sentido para o proto3 quando combinada com outros recursos, como a remoção da presença de campo para primitivas e a remoção de valores padrão superiores.

Não sou desenvolvedor de protobuf e não sou autoritário sobre o assunto, mas ainda espero que a explicação seja útil.

Eric Anderson
fonte
23
Sim. Veja também esta explicação extensa de coisas que podem dar terrivelmente errado nos campos obrigatórios: capnproto.org/…
Kenton Varda
8
Opcional não é removido; tudo é opcional no proto3. Mas sim, a visibilidade do campo (has_field) foi removida para primitivas . Se você precisar de visibilidade em campo, use wrappers.proto, que possui mensagens como StringValue. Como são mensagens, has_field está disponível. Isso é efetivamente "boxe", o que é comum em muitos idiomas.
Eric Anderson
9
Pelo contrário, parece que "opcional" foi removido no proto3. Todo campo existe e é preenchido com um valor padrão. Você não tem como saber se o campo primitivo foi preenchido pelo usuário ou por padrão. Os campos da mensagem, que são basicamente ponteiros, são opcionais, pois podem ter um valor nulo.
Vagrant
14
Eu me sinto como protobuf é uma linguagem concebida expressamente para começar flame wars
Randy L
5
Parece que a maioria das pessoas não quer fazer a versão de suas APIs. É mais fácil para eles tornar tudo opcional para "compatibilidade com versões anteriores".
Holoceo 9/11
41

Você pode encontrar a explicação nesta questão do Github protobuf :

Eliminamos os campos obrigatórios no proto3 porque os campos obrigatórios são geralmente considerados prejudiciais e violam a semântica de compatibilidade do protobuf. A idéia geral de usar o protobuf é que ele permite adicionar / remover campos da definição de protocolo e ainda ser totalmente compatível com versões anteriores / anteriores de binários novos / antigos. Os campos obrigatórios quebram isso. Você nunca pode adicionar com segurança um campo obrigatório a uma definição .proto, nem remover um campo obrigatório existente com segurança, pois essas duas ações quebram a compatibilidade do cabo. Por exemplo, se você adicionar um campo obrigatório a uma definição .proto, os binários criados com a nova definição não poderão analisar dados serializados usando a definição antiga, porque o campo obrigatório não está presente nos dados antigos. Em um sistema complexo onde. As definições de proto são compartilhadas amplamente entre muitos componentes diferentes do sistema, adicionando / removendo campos obrigatórios poderia facilmente derrubar várias partes do sistema. Vimos problemas de produção causados ​​por isso várias vezes e é praticamente proibido em qualquer lugar do Google para qualquer um adicionar / remover campos obrigatórios. Por esse motivo, removemos completamente os campos obrigatórios no proto3.

Após a remoção de "obrigatório", "opcional" é apenas redundante, portanto também removemos "opcional".

maiyang
fonte
6
Eu não entendo; qual é a diferença entre soltar uma mensagem após a desserialização e desserialização? ele será descartado pelo cliente mais antigo, pois não contém um campo necessário (por exemplo, id).
Shmuel H.
6
Estou inclinado a concordar com @ShmuelH. os campos obrigatórios farão parte de uma API de uma maneira ou de outra. Bem, isso é suportado automaticamente por meio da sintaxe dada a ambas as partes ou oculta no back-end, ainda está lá. Pode também torná-lo visível na definição api
Cruncher
7
Eu concordo totalmente com @ShmuelH. os campos são obrigatórios em uma API de uma maneira ou de outra e é útil para o cliente saber disso. Isso me faz pensar que ainda não conseguimos o controle de versão ainda.
patrickbarker
6
Outra votação para @ShmuelH. Se você alterar sua API de maneira incompatível com versões anteriores (adicionando um campo obrigatório), certamente deseja que seu analisador detecte isso? Versão de suas APIs! Você pode até fazê-lo completamente no Protobuf, se quiser, usando oneof { MessageV1, MessageV2, etc. }.
Timmmm 04/12/19
1
Não poderia justificar ter campos obrigatórios inicialmente. E adicionar um campo obrigatório é uma alteração incompatível e geralmente deve ser tratada pela alteração da versão do protocolo (ou seja, um novo tipo de mensagem).
kan