English for Protocol Buffers (Protobuf) Developers
Vocabulary for developers defining Protocol Buffers schemas — field numbers, wire format, and backward compatibility — for teams discussing serialization contracts in English.
Most Protobuf disagreements in review are really about schema evolution — whether a change is safe for services that haven’t redeployed yet. Having precise vocabulary for compatibility lets a reviewer say exactly why a change is risky, instead of a vague “that might break something.”
Schema Basics
.proto file — the schema definition file describing messages and their fields, from which Protobuf generates typed code for every target language a project uses.
“Don’t hand-edit the generated Go structs — change the .proto file and regenerate, or your fix disappears on the next codegen run.”
Message — a structured data type defined in a .proto file, roughly analogous to a class or struct, composed of typed, numbered fields.
“Add a new message instead of overloading this one with unrelated optional fields — it’s getting hard to tell what a valid instance even looks like.”
Field number — the small integer tag assigned to each field in a message, used in the binary wire format instead of the field’s name; this number, not the name, is what actually identifies the field on the wire.
“You can rename this field freely — just never change or reuse its field number, since that’s what actually identifies it in the encoded bytes.”
Wire Format and Encoding
Wire format — the compact binary encoding Protobuf uses to serialize messages, built around field numbers and types rather than field names, which is what makes it smaller and faster to parse than JSON.
“There’s no field name in the actual bytes on the wire — that’s why the field number is permanent and the field name is just a code-generation convenience.”
Varint — a variable-length integer encoding Protobuf uses for most numeric types, where small values take fewer bytes, which is part of why Protobuf payloads are typically smaller than equivalent JSON.
“Small counters like this cost almost nothing on the wire — varint encoding means a value under 128 takes a single byte.”
Compatibility
Backward compatibility — a schema change that doesn’t break older clients or servers still running the previous schema version, which is the default assumption Protobuf’s design optimizes for.
“Adding a new optional field is backward compatible — old binaries just ignore the field they don’t know about.”
Breaking change (in Protobuf) — reusing a field number for a different field, changing a field’s type incompatibly, or renumbering an existing field, any of which corrupts decoding for services on a different schema version.
“Reusing field number 4 for a different type is the single most dangerous thing you can do here — an old service will misinterpret the bytes entirely, not just fail cleanly.”
Reserved fields/numbers — explicitly marking a removed field’s number (and often its name) as reserved so it can never accidentally be reused by a future field, protecting against exactly that class of breaking change.
“Mark field 7 as reserved after removing it — that way nobody adds a new field with that number six months from now and silently breaks every service still on the old schema.”
Common Mistakes
- Renaming a field and assuming that alone is safe, without checking whether its field number was also changed.
- Reusing a deleted field’s number for a new, unrelated field instead of marking it reserved.
- Treating Protobuf compatibility rules as optional style preferences rather than the mechanism that keeps mixed-version services from silently corrupting data.
Practice Exercise
- Explain, in two sentences, why the field number matters more than the field name in Protobuf’s wire format.
- Write a short PR comment explaining why reusing a removed field’s number is unsafe and reserving it instead.
- Draft a message distinguishing a backward-compatible schema change from a breaking one for a teammate proposing a field type change.
Related Resources
- English for gRPC Web Developers
- English for OpenAPI and Swagger Developers
- English for Kafka Streaming Developers
Navigating the Nuances: Precision in Technical Communication
Let’s be honest – even native English speakers sometimes struggle to articulate precisely what they need when working with complex data formats like Protocol Buffers. For non-native speakers, the subtle differences in phrasing and expectation can create significant roadblocks. It’s not just about knowing the words for field_number or wire_format; it’s about conveying your intent clearly and confidently within a professional context. A misplaced word can lead to misunderstandings, delays, and ultimately, rework.
One common area of confusion arises during code reviews. Imagine receiving this comment on a pull request: “Consider increasing the field number for user_id – it’s currently colliding with a previously unused field.” The immediate reaction might be frustration if you don’t understand why that collision is problematic. A native speaker would instinctively recognize this as a concern about backward compatibility and potential data corruption down the line. However, someone less comfortable with technical English might simply focus on the instruction itself without fully grasping the underlying rationale. It’s crucial to respond thoughtfully, perhaps saying something like, “Okay, I understand the concern regarding field number collisions and backward compatibility. I’ll adjust it to avoid conflicts and ensure our schema remains robust.” This demonstrates not just understanding the what but also the why.
Another scenario involves describing changes in a pull request description. Instead of simply stating “Updated user profile data,” which is vague, try something like: “Implemented a new Protobuf message for UserProfile, aligning with the agreed-upon schema version 2.0. This includes adding fields for phone_number and date_of_birth, ensuring backward compatibility with existing versions through careful field number assignments as outlined in the serialization contract.” This level of detail, while potentially longer, drastically reduces ambiguity and provides context for reviewers to understand your design choices. It shows you’ve considered the broader implications beyond just modifying the data itself.
Finally, Slack conversations often require concise but precise communication. A developer might type: “Hey team, can someone double-check the Protobuf definitions for the order processing service? I’m seeing potential issues with how we’re handling multiple addresses – need to confirm the wire format is correctly optimized for minimal bandwidth.” The key here is using industry-specific vocabulary confidently and ensuring you’ve clearly articulated the specific area of concern (wire format optimization in this case).
syntax = "proto3";
message UserProfile {
string user_id = 1;
string name = 2;
int32 age = 3;
repeated string email_addresses = 4;
}