Mengapa diperlukan dan opsional dihapus dalam Protokol Buffer 3

216

Saya baru-baru ini menggunakan gRPCdengan proto3, dan saya perhatikan itu requireddan optionaltelah dihapus dalam sintaks baru.

Adakah yang bisa menjelaskan mengapa diharuskan / opsional dihapus di proto3? Kendala semacam itu sepertinya perlu untuk membuat definisi menjadi kuat.

sintaks proto2:

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

sintaks proto3:

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

Jawaban:

393

Kegunaan requiredtelah menjadi jantung dari banyak perdebatan dan nyala api. Kamp-kamp besar telah ada di kedua sisi. Satu kamp suka menjamin nilai ada dan bersedia hidup dengan keterbatasannya, tetapi kamp lainnya merasa requiredberbahaya atau tidak membantu karena tidak dapat ditambahkan atau dihilangkan dengan aman.

Biarkan saya menjelaskan lebih banyak alasan mengapa requiredbidang harus digunakan hemat. Jika Anda sudah menggunakan proto, Anda tidak bisa menambahkan bidang yang diperlukan karena aplikasi lama tidak akan menyediakan bidang itu dan aplikasi secara umum tidak menangani kegagalan dengan baik. Anda dapat memastikan bahwa semua aplikasi lama di-upgrade terlebih dahulu, tetapi bisa dengan mudah membuat kesalahan dan itu tidak membantu jika Anda menyimpan protos di datastore apa pun (bahkan berumur pendek, seperti memcached). Situasi yang sama berlaku saat menghapus bidang yang wajib diisi.

Banyak bidang wajib "jelas" diperlukan sampai ... tidak. Katakanlah Anda memiliki idbidang untuk suatu Getmetode. Itu jelas diperlukan. Kecuali, nanti Anda mungkin perlu mengubah iddari int ke string, atau int32 ke int64. Itu membutuhkan penambahan muchBetterIdbidang baru , dan sekarang Anda dibiarkan dengan idbidang lama yang harus ditentukan, tetapi akhirnya benar-benar diabaikan.

Ketika kedua masalah tersebut digabungkan, jumlah requiredbidang yang menguntungkan menjadi terbatas dan kamp-kamp berdebat tentang apakah masih memiliki nilai. Lawan dari requiredtidak harus menentang gagasan itu, tetapi bentuknya saat ini. Beberapa menyarankan untuk mengembangkan perpustakaan validasi yang lebih ekspresif yang dapat memeriksa requiredbersama dengan sesuatu yang lebih maju seperti name.length > 10, sementara juga memastikan untuk memiliki model kegagalan yang lebih baik.

Proto3 secara keseluruhan tampaknya mendukung kesederhanaan, dan requiredpenghapusan lebih sederhana. Tapi mungkin lebih meyakinkan, menghapus requiredmasuk akal untuk proto3 ketika dikombinasikan dengan fitur-fitur lain, seperti penghapusan kehadiran bidang untuk primitif dan penghapusan nilai default utama.

Saya bukan pengembang protobuf dan sama sekali tidak otoritatif tentang masalah ini, tapi saya masih berharap penjelasannya bermanfaat.

Eric Anderson
sumber
23
Ya. Lihat juga penjelasan lengkap tentang hal-hal yang bisa salah dengan bidang yang diperlukan: capnproto.org/…
Kenton Varda
8
Opsional tidak dihapus; semuanya opsional di proto3. Tapi ya, visibilitas bidang (has_field) telah dihapus karena primitif . Jika Anda membutuhkan visibilitas bidang, gunakan wrappers.proto yang memiliki pesan seperti StringValue. Karena itu adalah pesan, has_field tersedia. Ini secara efektif "tinju" yang umum dalam banyak bahasa.
Eric Anderson
9
Sebaliknya, sepertinya "opsional" telah dihapus di proto3. Setiap bidang ada, dan diisi dengan nilai default. Anda tidak memiliki cara untuk mengetahui apakah bidang primitif diisi oleh pengguna, atau secara default. Bidang pesan, yang pada dasarnya adalah pointer, adalah opsional, karena dapat memiliki nilai nol.
Vagrant
15
Saya merasa seperti protobuf adalah bahasa yang dirancang secara tegas untuk memulai perang api
Randy L
5
Sepertinya kebanyakan orang tidak ingin versi API mereka. Lebih mudah bagi mereka untuk membuat semuanya opsional untuk "kompatibilitas mundur".
Holoceo
42

Anda dapat menemukan penjelasan dalam masalah Github protobuf ini :

Kami menjatuhkan bidang yang diperlukan di proto3 karena bidang yang diperlukan umumnya dianggap berbahaya dan melanggar semantik kompatibilitas protobuf. Seluruh ide menggunakan protobuf adalah memungkinkan Anda untuk menambah / menghapus bidang dari definisi protokol Anda sementara masih sepenuhnya maju / mundur kompatibel dengan binari baru / lama. Namun, bidang yang harus diisi rusak ini. Anda tidak pernah dapat dengan aman menambahkan bidang yang diperlukan ke definisi .proto, juga tidak dapat dengan aman menghapus bidang yang diperlukan karena kedua tindakan ini merusak kompatibilitas kawat. Misalnya, jika Anda menambahkan bidang yang diperlukan ke definisi .proto, biner yang dibangun dengan definisi baru tidak akan dapat mengurai data yang diserialisasi menggunakan definisi lama karena bidang yang diperlukan tidak ada dalam data lama. Dalam sistem yang kompleks di mana. definisi proto dibagikan secara luas di berbagai komponen sistem, menambah / menghapus bidang yang diperlukan dapat dengan mudah menjatuhkan beberapa bagian sistem. Kami telah melihat masalah produksi yang disebabkan oleh ini beberapa kali dan itu cukup dilarang di mana-mana di dalam Google untuk siapa pun untuk menambah / menghapus bidang yang diperlukan. Untuk alasan ini kami sepenuhnya menghapus bidang yang diperlukan di proto3.

Setelah penghapusan "wajib", "opsional" hanya berlebihan, jadi kami juga menghapus "opsional".

maiyang
sumber
6
Saya tidak mengerti; apa perbedaan antara menjatuhkan pesan setelah deserializing dan deserialization? itu akan dijatuhkan oleh klien yang lebih lama karena tidak berisi bidang yang diperlukan (misalnya id).
Shmuel H.
6
Saya cenderung setuju dengan @ShmuelH. bidang yang diperlukan akan menjadi bagian dari api satu atau lain cara. Nah itu didukung secara otomatis melalui sintaks yang diberikan kepada kedua belah pihak, atau disembunyikan di backend, itu masih ada. Semoga juga membuatnya terlihat dalam definisi api
Cruncher
7
Saya sangat setuju dengan @ShmuelH. bidang diperlukan dalam API dengan satu atau lain cara dan bermanfaat bagi pelanggan untuk mengetahui hal ini. Ini membuat saya berpikir kita belum mendapatkan versi yang benar.
patrickbarker
6
Voting lain untuk @ShmuelH. Jika Anda mengubah API Anda dengan cara yang tidak kompatibel ke belakang (menambahkan bidang yang diperlukan), maka tentu Anda ingin parser Anda mendeteksi itu? Versi API Anda! Anda bahkan dapat melakukannya sepenuhnya di Protobuf jika Anda mau, menggunakan oneof { MessageV1, MessageV2, etc. }.
Timmmm
1
Itu tidak bisa membenarkan memiliki bidang yang dibutuhkan pada awalnya. Dan menambahkan bidang yang diperlukan adalah perubahan yang tidak kompatibel dan biasanya harus ditangani oleh perubahan versi protokol (yaitu jenis pesan baru).
kan