Pourquoi requis et facultatif est supprimé dans les tampons de protocole 3

216

J'utilise récemment gRPCavec proto3, et je l'ai remarqué requiredet optionala été supprimé dans la nouvelle syntaxe.

Quelqu'un pourrait-il bien vouloir expliquer pourquoi les éléments obligatoires / facultatifs sont supprimés dans proto3? Ce type de contraintes semble juste nécessaire pour rendre la définition robuste.

syntaxe proto2:

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

syntaxe proto3:

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

Réponses:

393

L'utilité de requireda été au cœur de nombreux débats et guerres incendiaires. De grands camps ont existé des deux côtés. Un camp aimait garantir qu'une valeur était présente et était prêt à vivre avec ses limites, mais l'autre camp se sentait requireddangereux ou inutile car il ne peut pas être ajouté ou supprimé en toute sécurité.

Permettez-moi d'expliquer davantage les raisons pour lesquelles les requiredchamps doivent être utilisés avec parcimonie. Si vous utilisez déjà un proto, vous ne pouvez pas ajouter un champ obligatoire car les anciennes applications ne fourniront pas ce champ et les applications en général ne gèrent pas bien l'échec. Vous pouvez vous assurer que toutes les anciennes applications sont mises à niveau en premier, mais il peut être facile de faire une erreur et cela n'aide pas si vous stockez les protos dans n'importe quel magasin de données (même de courte durée, comme memcached). Le même type de situation s'applique lors de la suppression d'un champ obligatoire.

De nombreux champs obligatoires étaient "évidemment" requis jusqu'à ce qu'ils ne l'étaient pas. Disons que vous avez un idchamp pour une Getméthode. C'est évidemment nécessaire. Sauf que plus tard, vous devrez peut-être modifier l' idint de chaîne en int, ou int32 en int64. Cela nécessite l'ajout d'un nouveau muchBetterIdchamp, et maintenant vous vous retrouvez avec l'ancien idchamp qui doit être spécifié, mais est finalement complètement ignoré.

Lorsque ces deux problèmes sont combinés, le nombre de requiredchamps bénéfiques devient limité et les camps se demandent s'il a encore de la valeur. Les opposants requiredn'étaient pas nécessairement contre l'idée, mais sa forme actuelle. Certains ont suggéré de développer une bibliothèque de validation plus expressive qui pourrait vérifier requiredquelque chose de plus avancé name.length > 10, tout en s'assurant d'avoir un meilleur modèle de défaillance.

Dans l'ensemble, Proto3 semble favoriser la simplicité et la requiredsuppression est plus simple. Mais peut-être plus convaincant, la suppression de requiredsens pour proto3 lorsqu'elle est combinée avec d'autres fonctionnalités, comme la suppression de la présence de champ pour les primitives et la suppression des valeurs par défaut écrasantes.

Je ne suis pas un développeur de protobuf et je n'ai aucune autorité sur le sujet, mais j'espère toujours que l'explication sera utile.

Eric Anderson
la source
23
Oui. Voir également cette explication détaillée des choses qui peuvent mal tourner avec les champs obligatoires: capnproto.org/…
Kenton Varda
9
Facultatif n'est pas supprimé; tout est facultatif dans proto3. Mais oui, la visibilité des champs (has_field) a été supprimée pour les primitives . Si vous avez besoin de visibilité sur le terrain, utilisez wrappers.proto qui contient des messages comme StringValue. Puisqu'il s'agit de messages, has_field est disponible. Il s'agit en fait de "boxe" qui est courante dans de nombreuses langues.
Eric Anderson
9
Au contraire, il semble que "facultatif" ait été supprimé dans proto3. Chaque champ existe et est rempli avec une valeur par défaut. Vous n'avez aucun moyen de savoir si le champ primitif a été rempli par l'utilisateur, ou par défaut. Les champs de message, qui sont essentiellement des pointeurs, sont facultatifs, car ils peuvent avoir une valeur nulle.
Vagrant
15
j'ai l'impression que protobuf est un langage conçu expressément pour déclencher des guerres de flammes
Randy L
5
Il semble que la plupart des gens ne souhaitent pas mettre à jour leurs API. Il leur est plus facile de tout rendre facultatif pour la «compatibilité descendante».
Holoceo
42

Vous pouvez trouver l'explication dans ce numéro de protobuf Github :

Nous avons supprimé les champs obligatoires dans proto3 car les champs obligatoires sont généralement considérés comme nuisibles et violant la sémantique de compatibilité de protobuf. L'idée générale de l'utilisation de protobuf est qu'elle vous permet d'ajouter / supprimer des champs de votre définition de protocole tout en étant entièrement compatible avec les versions binaires plus récentes / plus anciennes. Les champs obligatoires rompent cependant. Vous ne pouvez jamais ajouter en toute sécurité un champ obligatoire à une définition .proto, ni supprimer en toute sécurité un champ obligatoire existant car ces deux actions interrompent la compatibilité des fils. Par exemple, si vous ajoutez un champ obligatoire à une définition .proto, les fichiers binaires créés avec la nouvelle définition ne pourront pas analyser les données sérialisées en utilisant l'ancienne définition car le champ requis n'est pas présent dans les anciennes données. Dans un système complexe où. les définitions de prototypes sont largement partagées entre de nombreux composants différents du système, l'ajout / la suppression de champs requis pourrait facilement faire tomber plusieurs parties du système. Nous avons vu des problèmes de production à plusieurs reprises et il est pratiquement interdit partout dans Google pour quiconque d'ajouter / supprimer des champs obligatoires. Pour cette raison, nous avons complètement supprimé les champs obligatoires dans proto3.

Après la suppression de «requis», «facultatif» est simplement redondant, nous avons donc également supprimé «facultatif».

maiyang
la source
6
Je ne comprends pas; Quelle est la différence entre la suppression d'un message après la désérialisation et la désérialisation? il sera supprimé par l'ancien client car il ne contient pas de champ nécessaire (par exemple, id).
Shmuel H.
6
Je suis enclin à être d'accord avec @ShmuelH. les champs obligatoires vont faire partie d'une API d'une manière ou d'une autre. Eh bien, cela est pris en charge automatiquement par la syntaxe donnée aux deux parties, ou caché dans le backend, il est toujours là. Peut aussi bien le rendre visible dans la définition de l'API
Cruncher
7
Je suis totalement d'accord avec @ShmuelH. les champs sont requis d'une manière ou d'une autre dans une API et il est utile que le client le sache. Cela me fait penser que nous n'avons tout simplement pas encore réussi le versioning.
patrickbarker
6
Un autre vote pour @ShmuelH. Si vous modifiez votre API d'une manière incompatible en amont (en ajoutant un champ obligatoire), alors vous voulez sûrement que votre analyseur le détecte? Version vos API! Vous pouvez même le faire complètement dans Protobuf si vous le souhaitez, en utilisant oneof { MessageV1, MessageV2, etc. }.
Timmmm
1
Cela ne pouvait pas justifier d'avoir initialement requis des champs. Et l'ajout d'un champ obligatoire est un changement incompatible et doit généralement être géré par un changement de version du protocole (c'est-à-dire un nouveau type de message).
kan