Warum erforderlich und optional, wird in Protokollpuffern 3 entfernt

214

Ich verwende vor kurzem gRPCmit proto3, und ich habe das bemerkt requiredund optionalwurde in neuer Syntax entfernt.

Würde jemand freundlich erklären, warum erforderliche / optionale in proto3 entfernt werden? Solche Einschränkungen scheinen nur notwendig zu sein, um die Definition robust zu machen.

Syntax proto2:

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

Syntax proto3:

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

Antworten:

388

Die Nützlichkeit von requiredstand im Mittelpunkt vieler Debatten und Flammenkriege. Auf beiden Seiten gab es große Lager. Ein Lager garantierte gern, dass ein Wert vorhanden war und bereit war, mit seinen Grenzen zu leben, aber das andere Lager fühlte sich requiredgefährlich oder nicht hilfreich an, da es nicht sicher hinzugefügt oder entfernt werden kann.

Lassen Sie mich näher erläutern, warum requiredFelder sparsam verwendet werden sollten. Wenn Sie bereits ein Proto verwenden, können Sie kein erforderliches Feld hinzufügen, da alte Anwendungen dieses Feld nicht bereitstellen und Anwendungen im Allgemeinen den Fehler nicht gut behandeln. Sie können sicherstellen, dass alle alten Anwendungen zuerst aktualisiert werden. Es kann jedoch leicht zu Fehlern kommen, und es hilft nichts, wenn Sie die Protos in einem Datenspeicher speichern (auch nur von kurzer Dauer, z. B. zwischengespeichert). Die gleiche Situation gilt beim Entfernen eines erforderlichen Feldes.

Viele Pflichtfelder waren "offensichtlich" erforderlich, bis ... sie es nicht waren. Angenommen, Sie haben ein idFeld für eine GetMethode. Das ist natürlich erforderlich. Außer, dass Sie später möglicherweise idvon int in string oder int32 in int64 ändern müssen. Das erfordert das Hinzufügen eines neuen muchBetterIdFeldes, und jetzt mit dem alten bleiben idFeld, muss angegeben werden, aber schließlich wird völlig ignoriert.

Wenn diese beiden Probleme kombiniert werden, wird die Anzahl der nützlichen requiredFelder begrenzt und die Lager streiten darüber, ob sie noch Wert haben. Die Gegner von requiredwaren nicht unbedingt gegen die Idee, sondern gegen ihre aktuelle Form. Einige schlugen vor, eine aussagekräftigere Validierungsbibliothek zu entwickeln, die requiredzusammen mit fortgeschritteneren Methoden überprüft werden kann name.length > 10und gleichzeitig ein besseres Fehlermodell gewährleistet.

Insgesamt scheint Proto3 die Einfachheit zu bevorzugen, und das requiredEntfernen ist einfacher. Aber vielleicht überzeugender war das Entfernen requiredfür proto3 in Kombination mit anderen Funktionen wie dem Entfernen der Feldpräsenz für Grundelemente und dem Entfernen überschreibender Standardwerte.

Ich bin kein Protobuf-Entwickler und in keiner Weise maßgeblich für dieses Thema, aber ich hoffe trotzdem, dass die Erklärung nützlich ist.

Eric Anderson
quelle
23
Ja. Siehe auch diese erweiterte Erklärung von Dingen, die mit erforderlichen Feldern schrecklich schief gehen können: capnproto.org/…
Kenton Varda
8
Optional wird nicht entfernt; in proto3 ist alles optional. Aber ja, Feld Sichtbarkeit (has_field) wurde entfernt Primitiven . Wenn Sie Sichtbarkeit vor Ort benötigen, verwenden Sie wrappers.proto mit Nachrichten wie StringValue. Da es sich um Nachrichten handelt, ist has_field verfügbar. Dies ist effektiv "Boxen", was in vielen Sprachen üblich ist.
Eric Anderson
9
Im Gegenteil, es scheint, als ob "optional" in proto3 entfernt wurde. Jedes Feld ist vorhanden und wird mit einem Standardwert ausgefüllt. Sie können nicht wissen, ob das primitive Feld vom Benutzer oder standardmäßig ausgefüllt wurde. Nachrichtenfelder, die im Grunde genommen Zeiger sind, sind insofern optional, als sie einen Nullwert haben können.
Vagrant
14
Ich fühle mich wie Protobuf ist eine Sprache, die ausdrücklich entwickelt wurde, um Flammenkriege zu beginnen
Randy L
5
Scheint, als wollten die meisten Leute ihre APIs nicht versionieren. Es ist für sie einfacher, alles optional zu machen, um "Abwärtskompatibilität" zu gewährleisten.
Holoceo
41

Die Erklärung finden Sie in dieser protobuf Github-Ausgabe :

Wir haben erforderliche Felder in proto3 gelöscht, da erforderliche Felder im Allgemeinen als schädlich angesehen werden und die Kompatibilitätssemantik von protobuf verletzen. Die gesamte Idee der Verwendung von protobuf besteht darin, dass Sie Felder zu Ihrer Protokolldefinition hinzufügen / daraus entfernen können, während Sie weiterhin vollständig vorwärts / rückwärtskompatibel mit neueren / älteren Binärdateien sind. Erforderliche Felder unterbrechen dies jedoch. Sie können einer .proto-Definition niemals sicher ein erforderliches Feld hinzufügen oder ein vorhandenes erforderliches Feld sicher entfernen, da beide Aktionen die Drahtkompatibilität beeinträchtigen. Wenn Sie beispielsweise einer .proto-Definition ein erforderliches Feld hinzufügen, können mit der neuen Definition erstellte Binärdateien keine Daten analysieren, die mit der alten Definition serialisiert wurden, da das erforderliche Feld in alten Daten nicht vorhanden ist. In einem komplexen System wo. Proto-Definitionen werden von vielen verschiedenen Komponenten des Systems gemeinsam genutzt. Durch Hinzufügen / Entfernen der erforderlichen Felder können leicht mehrere Teile des Systems heruntergefahren werden. Wir haben mehrfach Produktionsprobleme gesehen, die dadurch verursacht wurden, und es ist überall in Google so gut wie verboten, dass jeder die erforderlichen Felder hinzufügt / entfernt. Aus diesem Grund haben wir die erforderlichen Felder in proto3 vollständig entfernt.

Nach dem Entfernen von "erforderlich" ist "optional" nur redundant, daher haben wir auch "optional" entfernt.

Maiyang
quelle
5
Ich verstehe es nicht; Was ist der Unterschied zwischen dem Löschen einer Nachricht nach dem Deserialisieren und dem Deserialisieren? Es wird vom älteren Client gelöscht, da es kein benötigtes Feld enthält (z. B. ID).
Shmuel H.
6
Ich bin geneigt, @ShmuelH zuzustimmen. Erforderliche Felder werden auf die eine oder andere Weise Teil einer API sein. Nun, das wird automatisch durch die Syntax unterstützt, die beiden Parteien gegeben wurde, oder im Backend versteckt, es ist immer noch da. Kann es auch in der API-Definition sichtbar machen
Cruncher
6
Ich stimme @ShmuelH voll und ganz zu. Felder werden in einer API auf die eine oder andere Weise benötigt und es ist nützlich, damit der Kunde dies weiß. Das lässt mich denken, dass wir die Versionierung noch nicht richtig verstanden haben.
Patrick Barker
5
Eine weitere Abstimmung für @ShmuelH. Wenn Sie Ihre API abwärtskompatibel ändern (indem Sie ein erforderliches Feld hinzufügen), möchten Sie sicher, dass Ihr Parser dies erkennt? Versionieren Sie Ihre APIs! Sie können es sogar vollständig in Protobuf ausführen, wenn Sie möchten oneof { MessageV1, MessageV2, etc. }.
Timmmm
1
Es konnte nicht rechtfertigen, dass zunächst Felder erforderlich waren. Das Hinzufügen eines erforderlichen Felds ist eine inkompatible Änderung und sollte normalerweise durch eine Änderung der Protokollversion (dh einen neuen Nachrichtentyp) behandelt werden.
Kan