Protobuf design patterns

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:

  1. 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.

  2. 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.

1

Where I work, the decision was taken to conceal the use of protobuf. We don’t distribute the .proto files between applications, but rather, any application that exposes a protobuf interface exports a client library which can talk to it.

I have only worked on one of these protobuf-exposing applications, but in that, each protobuf message corresponds to some concept in the domain. For each concept, there is a normal Java interface. There is then a converter class, which can take an instance of an implementation and construct an appropriate message object, and take a message object and construct an instance of an implementation of the interface (as it happens, usually a simple anonymous or local class defined inside the converter). The protobuf-generated message classes and converters together form a library which is used by both the application and the client library; the client library adds a small amount of code for setting up connections and sending and receiving messages.

Client applications then import the client library, and provide implementations of any interfaces they wish to send. Indeed, both sides do the latter thing.

To clarify, that means that if you have a request-response cycle where the client is sending a party invitation, and the server is responding with an RSVP, then the things involved are:

  • PartyInvitation message, written in the .proto file
  • PartyInvitationMessage class, generated by protoc
  • PartyInvitation interface, defined in the shared library
  • ActualPartyInvitation, a concrete implementation of PartyInvitation defined by the client app (not actually called that!)
  • StubPartyInvitation, a simple implementation of PartyInvitation defined by the shared library
  • PartyInvitationConverter, which can convert a PartyInvitation to a PartyInvitationMessage, and a PartyInvitationMessage to a StubPartyInvitation
  • RSVP message, written in the .proto file
  • RSVPMessage class, generated by protoc
  • RSVP interface, defined in the shared library
  • ActualRSVP, a concrete implementation of RSVP defined by the server app (also not actually called that!)
  • StubRSVP, a simple implementation of RSVP defined by the shared library
  • RSVPConverter, which can convert an RSVP to an RSVPMessage, and an RSVPMessage to a StubRSVP

The reason we have separate actual and stub implementations is that the actual implementations are generally JPA-mapped entity classes; the server either creates and persists them, or queries them up from the database, then hands them off to the protobuf layer to be transmitted. It wasn’t felt that it was appropriate to be creating instances of those classes on the receiving side of the connection, because they wouldn’t be tied to a persistence context. Furthermore, the entities often contain rather more data than is transmitted over the wire, so it wouldn’t even be possible to create intact objects on the receiving side. I am not entirely convinced that this was the right move, because it has left us with one more class per message than we would otherwise have.

Indeed, I am not entirely convinced that using protobuf at all was a good idea; if we’d stuck with plain old RMI and serialization, we wouldn’t have had to create nearly as many objects. In many cases, we could just have marked our entity classes as serializable and got on with it.

Now, having said all that, I have a friend who works at Google, on a codebase that makes heavy use of protobuf for communication between modules. They take a completely different approach: they don’t wrap the generated message classes at all, and enthusiastically pass them deep(ish) into their code. This is seen as a good thing, because it’s a simple of way of keeping interfaces flexible. There is no scaffolding code to keep in sync when messages evolve, and the generated classes provide all the necessary hasFoo() methods needed for receiving code to detect the presence or absence of fields that have been added over time. Bear in mind, though, that people who work at Google tend to be (a) rather clever and (b) a bit nuts.

2

To add on Andersons answer there is a fine line in nesting messages cleverly one into another and overdoing it. The problem is each message creates a new class behind the scenes and all sorts of accessors and handlers for the data. But there is a cost to that if you have to copy the data or change one value or compare the messages. Those processes can bee very slow and painful to do if you have a lot of data or are bound by time.

2

Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa Dịch vụ tổ chức sự kiện 5 sao Thông tin về chúng tôi Dịch vụ sinh nhật bé trai Dịch vụ sinh nhật bé gái Sự kiện trọn gói Các tiết mục giải trí Dịch vụ bổ trợ Tiệc cưới sang trọng Dịch vụ khai trương Tư vấn tổ chức sự kiện Hình ảnh sự kiện Cập nhật tin tức Liên hệ ngay Thuê chú hề chuyên nghiệp Tiệc tất niên cho công ty Trang trí tiệc cuối năm Tiệc tất niên độc đáo Sinh nhật bé Hải Đăng Sinh nhật đáng yêu bé Khánh Vân Sinh nhật sang trọng Bích Ngân Tiệc sinh nhật bé Thanh Trang Dịch vụ ông già Noel Xiếc thú vui nhộn Biểu diễn xiếc quay đĩa Dịch vụ tổ chức tiệc uy tín Khám phá dịch vụ của chúng tôi Tiệc sinh nhật cho bé trai Trang trí tiệc cho bé gái Gói sự kiện chuyên nghiệp Chương trình giải trí hấp dẫn Dịch vụ hỗ trợ sự kiện Trang trí tiệc cưới đẹp Khởi đầu thành công với khai trương Chuyên gia tư vấn sự kiện Xem ảnh các sự kiện đẹp Tin mới về sự kiện Kết nối với đội ngũ chuyên gia Chú hề vui nhộn cho tiệc sinh nhật Ý tưởng tiệc cuối năm Tất niên độc đáo Trang trí tiệc hiện đại Tổ chức sinh nhật cho Hải Đăng Sinh nhật độc quyền Khánh Vân Phong cách tiệc Bích Ngân Trang trí tiệc bé Thanh Trang Thuê dịch vụ ông già Noel chuyên nghiệp Xem xiếc khỉ đặc sắc Xiếc quay đĩa thú vị
Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa
Thiết kế website Thiết kế website Thiết kế website Cách kháng tài khoản quảng cáo Mua bán Fanpage Facebook Dịch vụ SEO Tổ chức sinh nhật