Dlaczego wymagane i opcjonalne jest usuwane w Buforach protokołów 3

214

Ostatnio używam gRPCz proto3i zauważyłem to requiredi optionalzostało usunięte w nowej składni.

Czy ktoś uprzejmie wyjaśni, dlaczego wymagane / opcjonalne są usuwane w proto3? Tego rodzaju ograniczenia wydają się konieczne, aby uczynić definicję solidną.

składnia proto2:

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

składnia proto3:

syntax = "proto3";
message SearchRequest {
  string query = 1;
  int32 page_number = 2;
  int32 result_per_page = 3;
}
yjzhang
źródło

Odpowiedzi:

390

Przydatność requiredbyła podstawą wielu debat i wojny z płomieniami. Po obu stronach istniały duże obozy. Jeden obóz lubił gwarantować, że wartość była obecna i był gotów żyć z jej ograniczeniami, ale drugi obóz czuł się requiredniebezpiecznie lub nieprzydatny, ponieważ nie można go bezpiecznie dodać ani usunąć.

Pozwól, że wyjaśnię ci więcej, dlaczego tak się dzieje required pola powinny być używane oszczędnie. Jeśli używasz już prototypu, nie możesz dodać wymaganego pola, ponieważ stare aplikacje nie będą go udostępniały, a aplikacje ogólnie nie radzą sobie z awarią. Możesz upewnić się, że wszystkie stare aplikacje są najpierw uaktualnione, ale może być łatwo popełnić błąd i nie pomaga, jeśli przechowujesz prototypy w dowolnym magazynie danych (nawet krótkotrwałym, takim jak memcached). Ten sam rodzaj sytuacji dotyczy usuwania wymaganego pola.

Wiele wymaganych pól było „oczywiście” wymaganych, dopóki… nie były. Powiedzmy, że masz idpole dla Getmetody. Jest to oczywiście wymagane. Poza tym później może być konieczna zmiana idz int na string lub z int32 na int64. To wymaga dodania nowego muchBetterIdpola, a teraz pozostało ci już stare idpole musi zostać określone, ale ostatecznie jest całkowicie ignorowane.

Po połączeniu tych dwóch problemów liczba korzystnych requiredpól staje się ograniczona, a obozy kłócą się o to, czy nadal ma ona wartość. Przeciwnicy requiredniekoniecznie byli przeciwni temu pomysłowi, ale jego obecnej formie. Niektórzy sugerowali opracowanie bardziej ekspresyjnej biblioteki sprawdzania poprawności, która mogłaby sprawdzić requiredwraz z czymś bardziej zaawansowanym, takim jakname.length > 10 , na przykład zapewniając lepszy model awarii.

Proto3 ogólnie wydaje się faworyzować prostotę, a requiredusuwanie jest prostsze. Ale może bardziej przekonujący, usuwającyrequired miało sens dla proto3 w połączeniu z innymi funkcjami, takimi jak usunięcie obecności pola dla prymitywów i usunięcie nadrzędnych wartości domyślnych.

Nie jestem deweloperem protobufów i nie jestem w żaden sposób autorytatywny w tym temacie, ale nadal mam nadzieję, że wyjaśnienie będzie przydatne.

Eric Anderson
źródło
23
Tak. Zobacz także to rozszerzone wyjaśnienie rzeczy, które mogą się potwornie nie udać w wymaganych polach: capnproto.org/…
Kenton Varda
8
Opcjonalne nie jest usuwane; wszystko jest opcjonalne w proto3. Ale tak, widoczność pola (has_field) została usunięta dla prymitywów . Jeśli potrzebujesz widoczności pola, użyj wrappers.proto, który zawiera takie wiadomości StringValue. Ponieważ są to wiadomości, pole has_ ​​jest dostępne. Jest to skutecznie „boks”, który jest powszechny w wielu językach.
Eric Anderson
9
Wręcz przeciwnie, wygląda na to, że w proto3 usunięto „opcjonalne”. Każde pole istnieje i jest wypełnione wartością domyślną. Nie masz możliwości sprawdzenia, czy pierwotne pole zostało wypełnione przez użytkownika, czy domyślnie. Pola wiadomości, które są w zasadzie wskaźnikami, są opcjonalne, ponieważ mogą mieć wartość zerową.
Vagrant
14
czuję się jak protobuf to język zaprojektowany specjalnie do rozpoczynania wojen z płomieniami
Randy L
5
Wygląda na to, że większość ludzi nie chce wersji API. Łatwiej im uczynić wszystko opcjonalnym dla „kompatybilności wstecznej”.
Holoceo,
41

Wyjaśnienie znajdziesz w tym numerze Github z protobufem :

Porzuciliśmy wymagane pola w proto3, ponieważ wymagane pola są ogólnie uważane za szkodliwe i naruszające semantykę zgodności protobuf. Cały pomysł użycia protobuf polega na tym, że pozwala on dodawać / usuwać pola z definicji protokołu, zachowując jednocześnie pełną kompatybilność do przodu / do tyłu z nowszymi / starszymi plikami binarnymi. Wymagane pola to jednak niszczą. Nigdy nie można bezpiecznie dodać wymaganego pola do definicji .proto, ani nie można bezpiecznie usunąć istniejącego wymaganego pola, ponieważ obie te czynności psują kompatybilność przewodów. Na przykład, jeśli dodasz wymagane pole do definicji .proto, pliki binarne zbudowane przy użyciu nowej definicji nie będą mogły analizować danych zserializowanych przy użyciu starej definicji, ponieważ wymagane pole nie występuje w starych danych. W złożonym systemie, w którym. definicje proto są szeroko udostępniane w wielu różnych komponentach systemu, dodawanie / usuwanie wymaganych pól może łatwo doprowadzić do awarii wielu części systemu. Wielokrotnie widzieliśmy problemy z produkcją i jest to prawie wszędzie zakazane w Google, aby każdy mógł dodawać / usuwać wymagane pola. Z tego powodu całkowicie usunęliśmy wymagane pola w proto3.

Po usunięciu „wymaganego”, „opcjonalne” jest po prostu zbędne, więc usunęliśmy również „opcjonalne”.

maiyang
źródło
6
Nie rozumiem; Jaka jest różnica między upuszczeniem wiadomości po deserializacji a deserializacją? zostanie odrzucony przez starszego klienta, ponieważ nie zawiera potrzebnego pola (np. id).
Shmuel H.
6
Jestem skłonny zgodzić się z @ShmuelH. wymagane pola będą w ten czy inny sposób częścią interfejsu API. Cóż, jest to obsługiwane automatycznie przez składnię przekazaną obu stronom lub ukryte w backendie, wciąż tam jest. Może także sprawić, że będzie to widoczne w definicji interfejsu API
Cruncher
7
Całkowicie zgadzam się z @ShmuelH. pola są wymagane w taki czy inny sposób w interfejsie API i jest to przydatne dla klienta, aby to wiedzieć. To sprawia, że ​​myślę, że nie mamy jeszcze wersji.
patrickbarker
6
Kolejny głos na @ShmuelH. Jeśli zmienisz interfejs API w sposób niezgodny wstecz (dodając wymagane pole), to na pewno chcesz, aby parser to wykrył? Wersja swoich interfejsów API! Możesz nawet zrobić to całkowicie w Protobuf, jeśli chcesz, używając oneof { MessageV1, MessageV2, etc. }.
Timmmm,
1
Nie mogło to uzasadniać początkowego posiadania wymaganych pól. Dodanie wymaganego pola jest niezgodną zmianą i zwykle powinno być obsługiwane przez zmianę wersji protokołu (tj. Nowy typ wiadomości).
kan