Protobuf design patterns
- by Monster Truck
I am evaluating Google Protocol Buffers for a Java based service (but am expecting language agnostic patterns). I have two questions:
The first is a broad general question:
What patterns are we seeing people use? Said patterns being related to class organization (e.g., messages per .proto file, packaging, and distribution) and message definition (e.g., repeated fields vs. repeated encapsulated fields*) etc.
There is very little information of this sort on the Google Protobuf Help pages and public blogs while there is a ton of information for established protocols such as XML.
I also have specific questions over the following two different patterns:
Represent messages in .proto files, package them as a separate jar, and ship it to target consumers of the service --which is basically the default approach I guess.
Do the same but also include hand crafted wrappers (not sub-classes!) around each message that implement a contract supporting at least these two methods (T is the wrapper class, V is the message class (using generics but simplified syntax for brevity):
public V toProtobufMessage() {
V.Builder builder = V.newBuilder();
for (Item item : getItemList()) {
builder.addItem(item);
}
return builder.setAmountPayable(getAmountPayable()).
setShippingAddress(getShippingAddress()).
build();
}
public static T fromProtobufMessage(V message_) {
return new T(message_.getShippingAddress(),
message_.getItemList(),
message_.getAmountPayable());
}
One advantage I see with (2) is that I can hide away the complexities introduced by V.newBuilder().addField().build() and add some meaningful methods such as isOpenForTrade() or isAddressInFreeDeliveryZone() etc. in my wrappers. The second advantage I see with (2) is that my clients deal with immutable objects (something I can enforce in the wrapper class).
One disadvantage I see with (2) is that I duplicate code and have to sync up my wrapper classes with .proto files.
Does anyone have better techniques or further critiques on any of the two approaches?
*By encapsulating a repeated field I mean messages such as this one:
message ItemList {
repeated item = 1;
}
message CustomerInvoice {
required ShippingAddress address = 1;
required ItemList = 2;
required double amountPayable = 3;
}
instead of messages such as this one:
message CustomerInvoice {
required ShippingAddress address = 1;
repeated Item item = 2;
required double amountPayable = 3;
}
I like the latter but am happy to hear arguments against it.