1-1-1 Best Practice
Die „1-1-1“-Best Practice empfiehlt die Strukturierung von Definitionen mit einer einzigen Top-Level-Entität (Nachricht, Enum oder Erweiterung) pro .proto-Datei, die einer einzelnen proto_library-Build-Regel entspricht. Dieser Ansatz fördert kleine, modulare Proto-Definitionen. Zu den wichtigsten Vorteilen gehören vereinfachte Refactorings, potenziell verbesserte Build-Zeiten und kleinere Binärgrößen aufgrund minimierter transitiver Abhängigkeiten.
Die 1-1-1-Best Practice besagt, dass jede proto_library und jede .proto-Datei so klein wie vernünftig gehalten werden sollte, wobei das Ideal ist:
- Eine
proto_library-Build-Regel - Eine Quell-
.proto-Datei - Eine Top-Level-Entität (Nachricht, Enum oder Erweiterung)
Die geringste Anzahl an Nachrichten, Enums, Erweiterungen und Diensten, die Sie vernünftigerweise haben können, erleichtert das Refactoring. Das Verschieben von Dateien, wenn sie getrennt sind, ist viel einfacher, als Nachrichten aus einer Datei mit anderen Nachrichten zu extrahieren.
Die Befolgung dieser Praxis kann die Build-Zeiten und die Binärgröße verbessern, indem die Größe Ihrer transitiven Abhängigkeiten in der Praxis reduziert wird: Wenn Code nur ein Enum verwenden muss, kann er sich unter einem 1-1-1-Design nur auf die .proto-Datei verlassen, die dieses Enum definiert, und es vermeiden, versehentlich eine große Menge transitiver Abhängigkeiten mitzuziehen, die möglicherweise nur von einer anderen Nachricht in derselben Datei verwendet werden.
Es gibt Fälle, in denen das 1-1-1-Ideal nicht möglich ist (zyklische Abhängigkeiten), nicht ideal ist (extrem konzeptionell gekoppelte Nachrichten, die Lesbarkeitsvorteile durch gemeinsame Platzierung haben) oder in denen einige der Nachteile nicht zutreffen (wenn eine .proto-Datei keine Importe hat, dann gibt es keine technischen Bedenken hinsichtlich der Größe transitiver Abhängigkeiten). Wie bei jeder Best Practice sollten Sie mit gutem Urteilsvermögen entscheiden, wann Sie von der Richtlinie abweichen.
Ein Bereich, in dem die Modularität von Proto-Schema-Dateien wichtig ist, ist die Erstellung von gRPC-Definitionen. Die folgende Reihe von Proto-Dateien zeigt eine modulare Struktur.
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);
}
Die Service-Definition und jede der Nachrichten-Definitionen befinden sich in ihrer eigenen Datei, und Sie verwenden Includes, um Zugriff auf die Nachrichten aus anderen Schema-Dateien zu erhalten.
In diesem Beispiel sind Student, StudentId und FullName Domänentypen, die wiederverwendbar über Anfragen und Antworten sind. Die Top-Level-Anfragen und -Antworten sind eindeutig für jeden Service + Methode.
Wenn Sie später ein middle_name-Feld zur FullName-Nachricht hinzufügen müssen, müssen Sie nicht jede einzelne Top-Level-Nachricht mit diesem neuen Feld aktualisieren. Ebenso, wenn Sie Student mit weiteren Informationen aktualisieren müssen, erhalten alle Anfragen und Antworten das Update. Darüber hinaus kann StudentId zu einer mehrteiligen ID aktualisiert werden.
Schließlich bedeutet das Einpacken selbst einfacher Typen wie StudentId als Nachricht, dass Sie einen Typ erstellt haben, der Semantik und konsolidierte Dokumentation besitzt. Für etwas wie FullName müssen Sie vorsichtig sein, wo diese PII protokolliert wird; dies ist ein weiterer Vorteil, diese Felder nicht in mehreren Top-Level-Nachrichten zu wiederholen. Sie können diese Felder an einer Stelle als sensibel kennzeichnen und von der Protokollierung ausschließen.