1-1-1 最佳實務
1-1-1 最佳實務是盡可能保持每個 proto_library 和 .proto 檔案小巧,理想情況是
- 一個
proto_library
建置規則 - 一個來源
.proto
檔案 - 一個頂層實體 (message、enum 或 extension)
盡可能減少 message、enum、extension 和 service 的數量,可以讓重構更容易。當檔案分離時,移動檔案比從包含其他 message 的檔案中提取 message 容易得多。
遵循此實務可以透過減少實際應用中傳遞依賴的大小,來幫助縮短建置時間和二進制檔案大小:當某些程式碼只需要使用一個 enum 時,在 1-1-1 設計下,它可以僅依賴定義該 enum 的 .proto 檔案,並避免意外引入大量可能僅由同一檔案中定義的另一個 message 使用的傳遞依賴。
在某些情況下,1-1-1 理想可能不可行 (循環依賴),不理想 (概念上極度耦合的 message 透過共置可以提高可讀性),或者某些缺點不適用 (當 .proto 檔案沒有 import 時,就不存在關於傳遞依賴大小的技術考量)。與任何最佳實務一樣,當需要偏離指南時,請運用良好的判斷力。
proto schema 檔案模組化很重要的一個地方是在建立 gRPC 定義時。以下一組 proto 檔案展示了模組化結構。
student_id.proto
edition = "2023";
package my.package;
message StudentId {
string value = 1;
}
full_name.proto
edition = "2023";
package my.package;
message FullName {
string family_name = 1;
string given_name = 2;
}
student.proto
edition = "2023";
package my.package;
import "student_id.proto";
import "full_name.proto";
message Student {
StudentId id = 1;
FullName name = 2;
}
create_student_request.proto
edition = "2023";
package my.package;
import "full_name.proto";
message CreateStudentRequest {
FullName name = 1;
}
create_student_response.proto
edition = "2023";
package my.package;
import "student.proto";
message CreateStudentResponse {
Student student = 1;
}
get_student_request.proto
edition = "2023";
package my.package;
import "student_id.proto";
message GetStudentRequest {
StudentId id = 1;
}
get_student_response.proto
edition = "2023";
package my.package;
import "student.proto";
message GetStudentResponse {
Student student = 1;
}
student_service.proto
edition = "2023";
package my.package;
import "create_student_request.proto";
import "create_student_response.proto";
import "get_student_request.proto";
import "get_student_response.proto";
service StudentService {
rpc CreateStudent(CreateStudentRequest) returns (CreateStudentResponse);
rpc GetStudent(GetStudentRequest) returns (GetStudentResponse);
}
service 定義和每個 message 定義都各自在自己的檔案中,並且您可以使用 include 來從其他 schema 檔案存取 message。
在此範例中,Student
、StudentId
和 FullName
是跨請求和回應可重複使用的網域類型。頂層請求和回應 proto 對於每個 service+method 都是唯一的。
如果您稍後需要在 FullName
message 中新增 middle_name
欄位,您將不需要使用該新欄位更新每個個別的頂層 message。同樣地,如果您需要使用更多資訊更新 Student
,則所有請求和回應都會獲得更新。此外,StudentId
可能會更新為多部分 ID。
最後,即使將像 StudentId
這樣的簡單類型包裝成 message,也意味著您建立了一個具有語意和整合文件化的類型。對於像 FullName
這樣的類型,您需要小心 PII 記錄的位置;這是不在多個頂層 message 中重複這些欄位的另一個優點。您可以將這些欄位在一個地方標記為敏感,並將其從記錄中排除。