Perché richiesto e facoltativo viene rimosso in Protocol Buffers 3


216

Di recente sto usando gRPCcon proto3, e l'ho notato requireded optionalè stato rimosso in una nuova sintassi.

Qualcuno spiegherebbe gentilmente perché sono richiesti / facoltativi rimossi in proto3? Un tale tipo di vincoli sembra solo necessario per rendere la definizione solida.

sintassi proto2:

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

sintassi proto3:

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

Risposte:


393

L'utilità di requiredè stata al centro di molti dibattiti e guerre di fiamma. Grandi campi sono esistiti da entrambe le parti. A un campo piaceva garantire la presenza di un valore ed era disposto a convivere con i suoi limiti, ma l'altro campo si sentiva requiredpericoloso o inutile in quanto non poteva essere aggiunto o rimosso in modo sicuro.

Consentitemi di spiegare meglio il ragionamento sul perché i requiredcampi dovrebbero essere usati con parsimonia. Se stai già utilizzando un proto, non puoi aggiungere un campo obbligatorio perché la vecchia applicazione non fornirà quel campo e le applicazioni in generale non gestiscono bene l'errore. Puoi assicurarti che tutte le vecchie applicazioni vengano aggiornate per prime, ma può essere facile commettere un errore e non aiuta se stai memorizzando i protos in qualsiasi archivio dati (anche di breve durata, come memcached). Lo stesso tipo di situazione si applica quando si rimuove un campo obbligatorio.

Molti campi obbligatori erano "ovviamente" obbligatori fino a quando ... non lo erano. Diciamo che hai un idcampo per un Getmetodo. Questo è ovviamente necessario. Tranne, in seguito potrebbe essere necessario modificare idda int a string o da int32 a int64. Ciò richiede l'aggiunta di un nuovo muchBetterIdcampo e ora ti rimane il vecchio idcampo che deve essere specificato, ma alla fine viene completamente ignorato.

Quando questi due problemi vengono combinati, il numero di benefici required campi diventa limitato e i campi discutono se ha ancora valore. Gli avversari di requirednon erano necessariamente contrari all'idea, ma alla sua forma attuale. Alcuni hanno suggerito di sviluppare una libreria di convalida più espressiva che potesse verificare requiredinsieme a qualcosa di più avanzato name.length > 10, assicurandosi anche di avere un modello di errore migliore.

Proto3 nel complesso sembra favorire la semplicità e required rimozione è più semplice. Ma forse più convincente, la rimozione del requiredsignificato ha senso per proto3 quando combinato con altre funzionalità, come la rimozione della presenza sul campo per le primitive e la rimozione di valori predefiniti prevalenti.

Non sono uno sviluppatore di protobuf e non sono in alcun modo autorevole sull'argomento, ma spero ancora che la spiegazione sia utile.


23
Sì. Vedi anche questa spiegazione estesa di cose che possono andare terribilmente sbagliate nei campi obbligatori: capnproto.org/…
Kenton Varda,

9
Opzionale non rimosso; tutto è facoltativo in proto3. Sì, la visibilità del campo (has_field) è stata rimossa per le primitive . Se hai bisogno di visibilità sul campo usa wrappers.proto che ha messaggi simili StringValue. Dal momento che sono messaggi, has_field è disponibile. Si tratta effettivamente di "boxe", che è comune in molte lingue.
Eric Anderson,

9
Al contrario, sembra che "opzionale" sia stato rimosso in proto3. Ogni campo esiste ed è compilato con un valore predefinito. Non hai modo di sapere se il campo primitivo è stato compilato dall'utente o per impostazione predefinita. I campi dei messaggi, che sono sostanzialmente dei puntatori, sono facoltativi, in quanto possono avere un valore nullo.
Vagrant

15
mi sento come protobuf è un linguaggio progettato espressamente per iniziare le guerre di fiamma
Randy L

5
Sembra che la maggior parte delle persone non voglia versioni della propria API. È più facile per loro rendere tutto opzionale per la "compatibilità con le versioni precedenti".
Holoceo,

42

Puoi trovare la spiegazione in questo protobuf problema di Github :

Abbiamo eliminato i campi obbligatori in proto3 perché i campi obbligatori sono generalmente considerati dannosi e violano la semantica di compatibilità di protobuf. L'idea generale di utilizzare protobuf è che consente di aggiungere / rimuovere campi dalla definizione del protocollo pur essendo pienamente compatibile con i binari più recenti / precedenti. I campi obbligatori interrompono questo però. Non è mai possibile aggiungere in modo sicuro un campo obbligatorio a una definizione .proto, né è possibile rimuovere in modo sicuro un campo obbligatorio esistente poiché entrambe queste azioni interrompono la compatibilità del filo. Ad esempio, se si aggiunge un campo obbligatorio a una definizione .proto, i binari creati con la nuova definizione non saranno in grado di analizzare i dati serializzati utilizzando la vecchia definizione perché il campo richiesto non è presente nei vecchi dati. In un sistema complesso dove. le definizioni di proto sono ampiamente condivise tra molti diversi componenti del sistema, l'aggiunta / rimozione di campi obbligatori potrebbe facilmente far cadere più parti del sistema. Abbiamo riscontrato problemi di produzione causati da questo più volte ed è praticamente vietato ovunque all'interno di Google per chiunque di aggiungere / rimuovere campi obbligatori. Per questo motivo abbiamo rimosso completamente i campi richiesti in proto3.

Dopo la rimozione di "richiesto", "opzionale" è semplicemente ridondante, quindi abbiamo rimosso anche "opzionale".


6
Non capisco; qual è la differenza tra la caduta di un messaggio dopo la deserializzazione e la deserializzazione? verrà eliminato dal client precedente poiché non contiene un campo necessario (ad es. id).
Shmuel H.

6
Sono propenso a concordare con @ShmuelH. i campi obbligatori faranno parte dell'API in un modo o nell'altro. Bene che è supportato automaticamente attraverso la sintassi fornita a entrambe le parti o nascosto nel back-end, è ancora lì. Può anche renderlo visibile nella definizione di api
Cruncher,

7
Sono totalmente d'accordo con @ShmuelH. i campi sono richiesti in un'API in un modo o nell'altro ed è utile che il cliente lo sappia. Questo mi fa pensare che non abbiamo ancora ottenuto il controllo delle versioni.
patrickbarker,

6
Un altro voto per @ShmuelH. Se modifichi la tua API in modo incompatibile con le versioni precedenti (aggiungendo un campo obbligatorio), sicuramente vuoi che il tuo parser lo rilevi? Versione le tue API! Puoi anche farlo completamente in Protobuf se vuoi, usando oneof { MessageV1, MessageV2, etc. }.
Timmmm,

1
Non poteva giustificare di aver inizialmente richiesto i campi. E l'aggiunta di un campo obbligatorio è una modifica incompatibile e di solito dovrebbe essere gestita dalla modifica della versione del protocollo (ovvero un nuovo tipo di messaggio).
kan
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.