Чому необхідні та необов’язкові видаляються у буферах протоколу 3


214

Я недавно з допомогою gRPCз proto3, і я помітив , що requiredі optionalбув вилучений в новому синтаксисі.

Хто-небудь люб’язно пояснить, чому обов'язкові / необов’язкові видаляються в proto3? Такі обмеження просто здаються необхідними, щоб зробити визначення надійним.

синтаксис proto2:

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

синтаксис proto3:

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

Відповіді:


390

Корисність requiredлежить в основі багатьох дебатів і вогненних воєн. Великі табори існували з обох сторін. Один табір любив гарантувати наявність цінності і був готовий жити з його обмеженнями, але інший табір відчувавrequired небезпечно чи не допомагає, оскільки його не можна безпечно додавати і не знімати.

Дозвольте мені пояснити більше міркувань, чому requiredполя повинні використовуватися сумлінно. Якщо ви вже використовуєте протокол, ви не можете додати обов'язкове поле, оскільки стара програма не надасть це поле, а програми, як правило, не справляються з відмовою. Ви можете переконатися, що спочатку оновлено всі старі програми, але помилка може бути легко, і це не допоможе, якщо ви зберігаєте протоколи в будь-якій сховищі даних (навіть короткочасній, як запам’ятовується). Така ж ситуація застосовується і при видаленні необхідного поля.

Багато обов'язкових полів були "очевидно" обов'язковими, поки ... вони не були. Скажімо, у вас є idполе для Getметоду. Це, очевидно, потрібно. Крім того, пізніше вам може знадобитися змінити idз int на рядок або int32 на int64. Для цього потрібно додати нове muchBetterIdполе, і тепер вам залишається старе idполе, яке потрібно вказати, але з часом воно повністю ігнорується.

Коли ці дві проблеми поєднуються, кількість вигідних requiredполів стає обмеженою, і табори сперечаються щодо того, чи має вона ще значення. Противники requiredне були обов'язково проти ідеї, а її теперішньої форми. Деякі запропонували розробити більш виразну бібліотеку перевірки, яка могла б перевірити requiredразом із чимось більш досконалим, як name.length > 10, наприклад , при цьому переконавшись, що є краща модель відмов.

Схоже, Proto3 загалом сприяє простоті, а requiredвидалення простіше. Але, можливо, більш переконливо, видалення має requiredсенс для proto3 у поєднанні з іншими функціями, такими як видалення присутності поля для примітивів та видалення переважаючих значень за замовчуванням.

Я не розробник протобуфа і жодним чином не авторитетний з цього приводу, але все ж сподіваюся, що пояснення корисне.


23
Так. Дивіться також це розширене пояснення речей, які можуть жахливо помилитися з обов'язковими полями: capnproto.org/…
Кентон Варда,

8
Необов’язково не видаляється; у proto3 все необов’язково. Але так, видимість поля (has_field) видалена для примітивів . Якщо вам потрібна видимість поля, використовуйте wrappers.proto, який містить такі повідомлення StringValue. Оскільки вони є повідомленнями, доступний has_field. Це ефективно "бокс", який є загальним для багатьох мов.
Ерік Андерсон

9
Навпаки, схоже, що "необов'язково" було видалено в прото3. Кожне поле існує і заповнюється значенням за замовчуванням. Ви не можете знати, чи примітивне поле заповнив користувач, або за замовчуванням. Поля повідомлень, які в основному є покажчиками, необов’язкові, оскільки вони можуть мати нульове значення.
Бродяга

14
я відчуваю, що протобуф - це мова, розроблена прямо для початку вогняних воєн
Ранді L

5
Схоже, більшість людей не хочуть версії своїх API. Їм простіше зробити все необов’язковим для "зворотної сумісності".
Голосео

41

Ви можете знайти пояснення в цьому протобуфі Github :

Ми заборонили обов'язкові поля в прото3, оскільки обов'язкові поля вважаються шкідливими та порушують семантику сумісності протобуфа. Вся ідея використання protobuf полягає в тому, що воно дозволяє додавати / видаляти поля з визначення протоколу, залишаючись повністю вперед / назад сумісними з новішими / старими бінарними файлами. Обов’язкові поля, однак, порушують це. Ніколи не можна безпечно додавати необхідне поле до визначення .proto, а також не можна безпечно видаляти наявне необхідне поле, оскільки обидва ці дії порушують сумісність проводів. Наприклад, якщо ви додасте необхідне поле до визначення .proto, бінарні файли, побудовані з новим визначенням, не зможуть проаналізувати дані, серіалізовані за допомогою старого визначення, тому що необхідне поле відсутнє в старих даних. У складній системі де. Визначення протоколів широко розподіляються між багатьма різними компонентами системи, додавання / видалення необхідних полів може легко збити кілька частин системи. Ми неодноразово спостерігали виробничі проблеми, викликані цим, і це майже заборонено скрізь у Google, щоб хто-небудь міг додавати / видаляти необхідні поля. З цієї причини ми повністю видалили потрібні поля в прото3.

Після видалення "потрібно", "необов'язково" просто зайве, тому ми також видалили "необов'язково".


6
Я не розумію; яка різниця між відкиданням повідомлення після десеріалізації та від десеріалізації? він буде скинутий старшим клієнтом, оскільки він не містить необхідного поля (наприклад, id).
Шмуель Х.

6
Я схильний погодитися з @ShmuelH. обов'язкові поля будуть так чи інакше частиною api. Добре, що автоматично підтримується через синтаксис, наданий обом сторонам або прихований у бекенді, він все ще є. Може також зробити його видимим у визначенні апі
Cruncher

7
Я повністю згоден з @ShmuelH. поля потрібні в API так чи інакше, і корисно, щоб клієнт це знав. Це змушує мене думати, що ми просто ще не отримали версію.
patrickbarker

6
Чергове голосування за @ShmuelH. Якщо ви змінюєте API невідповідним способом (додаючи обов'язкове поле), то, напевно, ви хочете, щоб ваш аналізатор це виявив? Версія своїх API! Ви навіть можете це зробити повністю в Protobuf, якщо хочете, використовуючи oneof { MessageV1, MessageV2, etc. }.
Timmmm

1
Це не могло виправдати спочатку необхідні поля. І додавання необхідного поля є несумісною зміною, і зазвичай слід обробляти зміну версії протоколу (тобто новий тип повідомлення).
кан
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.