Tại sao bắt buộc và tùy chọn bị xóa trong Bộ đệm giao thức 3


214

Gần đây tôi đang sử dụng gRPCvới proto3, và tôi đã nhận thấy rằng requiredoptionalđã được gỡ bỏ trong cú pháp mới.

Bất cứ ai cũng vui lòng giải thích tại sao yêu cầu / tùy chọn được loại bỏ trong proto3? Loại ràng buộc như vậy chỉ cần thiết để làm cho định nghĩa mạnh mẽ.

cú pháp proto2:

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

cú pháp proto3:

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

Câu trả lời:


388

Sự hữu ích của requiredđã là trung tâm của nhiều cuộc tranh luận và chiến tranh rực lửa. Trại lớn đã tồn tại ở cả hai bên. Một trại thích đảm bảo một giá trị đã có mặt và sẵn sàng sống với những hạn chế của nó nhưng trại kia cảm thấy requirednguy hiểm hoặc không có ích vì nó không thể được thêm vào một cách an toàn cũng không bị xóa.

Hãy để tôi giải thích thêm về lý do tại sao requiredcác trường nên được sử dụng một cách tiết kiệm. Nếu bạn đã sử dụng proto, bạn không thể thêm trường bắt buộc vì ứng dụng cũ sẽ không cung cấp trường đó và các ứng dụng nói chung không xử lý tốt lỗi. Bạn có thể đảm bảo rằng tất cả các ứng dụng cũ đều được nâng cấp trước, nhưng có thể dễ mắc lỗi và không có ích gì nếu bạn lưu trữ protos trong bất kỳ kho dữ liệu nào (ngay cả trong thời gian ngắn, như memcached). Loại tình huống tương tự được áp dụng khi loại bỏ một trường bắt buộc.

Nhiều trường bắt buộc là "rõ ràng" được yêu cầu cho đến khi ... chúng không. Giả sử bạn có một idtrường cho một Getphương thức. Đó rõ ràng là yêu cầu. Ngoại trừ, sau này bạn có thể cần thay đổi idtừ int thành chuỗi hoặc int32 thành int64. Đó là đòi hỏi thêm một mới muchBetterIdlĩnh vực, và bây giờ bạn là trái với cái cũ idtrường phải được xác định, nhưng cuối cùng là hoàn toàn bị bỏ qua.

Khi hai vấn đề đó được kết hợp, số lượng các requiredlĩnh vực có lợi trở nên hạn chế và các trại tranh luận về việc liệu nó có còn giá trị hay không. Các đối thủ của requiredkhông nhất thiết chống lại ý tưởng, nhưng hình thức hiện tại của nó. Một số đề xuất phát triển một thư viện xác nhận biểu cảm hơn có thể kiểm tra requiredcùng với một cái gì đó cao cấp hơn name.length > 10, đồng thời đảm bảo có một mô hình thất bại tốt hơn.

Proto3 tổng thể dường như thiên về sự đơn giản, và requiredviệc loại bỏ thì đơn giản hơn. Nhưng có lẽ thuyết phục hơn, loại bỏ requiredý nghĩa đối với proto3 khi kết hợp với các tính năng khác, như loại bỏ sự hiện diện của trường cho các nguyên thủy và loại bỏ các giá trị mặc định ghi đè.

Tôi không phải là nhà phát triển protobuf và không có thẩm quyền về chủ đề này, nhưng tôi vẫn hy vọng rằng lời giải thích này hữu ích.


23
Vâng. Xem thêm phần giải thích mở rộng này về những điều có thể trở nên sai lầm khủng khiếp với các trường bắt buộc: capnproto.org/iêu
Kenton Varda

8
Tùy chọn không bị xóa; tất cả mọi thứ là tùy chọn trong proto3. Nhưng có, khả năng hiển thị trường (has_field) đã bị xóa đối với nguyên thủy . Nếu bạn cần khả năng hiển thị trường, hãy sử dụng Wrappers.proto có thông báo như thế nào StringValue. Vì chúng là tin nhắn, has_field có sẵn. Đây thực sự là "quyền anh" vốn phổ biến trong nhiều ngôn ngữ.
Eric Anderson

9
Ngược lại, có vẻ như "tùy chọn" đã bị xóa trong proto3. Mỗi trường tồn tại và được điền vào một giá trị mặc định. Bạn không có cách nào để biết liệu trường nguyên thủy được điền bởi người dùng hay theo mặc định. Các trường thông báo, về cơ bản là các con trỏ, là tùy chọn, trong đó chúng có thể có giá trị null.
Vagrant

14
tôi cảm thấy như protobuf là một ngôn ngữ được thiết kế rõ ràng để bắt đầu các cuộc chiến nảy lửa
Randy L

5
Có vẻ như hầu hết mọi người không muốn phiên bản API của họ. Họ dễ dàng hơn trong việc biến mọi thứ thành tùy chọn cho "khả năng tương thích ngược".
Holoceo

41

Bạn có thể tìm thấy lời giải thích trong vấn đề protithuf Github này :

Chúng tôi đã bỏ các trường bắt buộc trong proto3 vì các trường bắt buộc thường được coi là có hại và vi phạm ngữ nghĩa tương thích của protobuf. Toàn bộ ý tưởng của việc sử dụng protobuf là nó cho phép bạn thêm / xóa các trường khỏi định nghĩa giao thức của bạn trong khi vẫn hoàn toàn chuyển tiếp / lùi tương thích với các nhị phân mới hơn / cũ hơn. Các trường bắt buộc phá vỡ điều này mặc dù. Bạn không bao giờ có thể thêm trường bắt buộc vào định nghĩa .proto một cách an toàn, cũng như không thể xóa trường bắt buộc hiện có một cách an toàn vì cả hai hành động này đều phá vỡ tính tương thích của dây. Ví dụ: nếu bạn thêm trường bắt buộc vào định nghĩa .proto, các nhị phân được xây dựng với định nghĩa mới sẽ không thể phân tích dữ liệu được tuần tự hóa bằng định nghĩa cũ vì trường bắt buộc không có trong dữ liệu cũ. Trong một hệ thống phức tạp đâu. định nghĩa proto được chia sẻ rộng rãi trên nhiều thành phần khác nhau của hệ thống, việc thêm / xóa các trường bắt buộc có thể dễ dàng đưa xuống nhiều phần của hệ thống. Chúng tôi đã thấy các vấn đề sản xuất gây ra bởi điều này nhiều lần và nó bị cấm khá nhiều ở mọi nơi trong Google để mọi người thêm / xóa các trường bắt buộc. Vì lý do này, chúng tôi đã loại bỏ hoàn toàn các trường bắt buộc trong proto3.

Sau khi loại bỏ "bắt buộc", "tùy chọn" chỉ là dư thừa nên chúng tôi cũng loại bỏ "tùy chọn".


6
Tôi không hiểu nó; sự khác biệt giữa việc bỏ một tin nhắn sau khi khử lưu huỳnh và khử lưu huỳnh là gì? nó sẽ bị rớt bởi máy khách cũ hơn vì nó không chứa trường cần thiết (ví dụ id).
Shmuel H.

6
Tôi có khuynh hướng đồng ý với @ShmuelH. các trường bắt buộc sẽ là một phần của api bằng cách này hay cách khác. Vâng, điều đó được hỗ trợ tự động thông qua cú pháp được cung cấp cho cả hai bên hoặc ẩn trong phần phụ trợ, nó vẫn ở đó. Cũng có thể làm cho nó hiển thị trong định nghĩa api
Cruncher

7
Tôi hoàn toàn đồng ý với @ShmuelH. các trường được yêu cầu theo cách này hay cách khác và nó hữu ích cho khách hàng biết điều này. Điều này khiến tôi nghĩ rằng chúng ta chưa có phiên bản đúng.
patrickbarker

6
Một phiếu bầu khác cho @ShmuelH. Nếu bạn thay đổi API theo cách không tương thích ngược (thêm trường bắt buộc), thì bạn có chắc chắn muốn trình phân tích cú pháp của mình phát hiện ra điều đó không? Phiên bản API của bạn! Bạn thậm chí có thể làm điều đó hoàn toàn trong Protobuf nếu bạn muốn, sử dụng oneof { MessageV1, MessageV2, etc. }.
Timmmm

1
Nó không thể biện minh cho việc có các trường bắt buộc ban đầu. Và việc thêm một trường bắt buộc là thay đổi không tương thích và thường phải được xử lý bằng thay đổi phiên bản giao thức (tức là một loại thông báo mới).
kan
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.