Introducing BERT and BERT-RPC: GitHub's new serialization and RPC protocol
github.com
github.com
I personally find thrift IDL trivial to manage and is probably the only sane way to support a dozen languages (statically and dynamically typed) in a type safe and efficient way.
BERT-RPC is simple, but what if you find your server too slow and needs to be rewritten in another language? I think the Thrift approach makes that simpler.
I just can’t. I find the entire concept behind IDLs and code generation abhorrent. Coming from a background in dynamic languages and automated testing, these ideas just seem silly.
The point of IDLs is to provide a stable, exact, portable and succinct definition of an inter-application protocol. In defining the protocol explicitly in a language neutral way, it is easier to ensure conformance and correctness of implementation.
As a side effect, it does make code generation easy, allows one to optionally apply static typing to ensure that messages are always correctly formed, and ensures a _DRY_ approach across the board.
You could just as easily implement poorly defined interfaces using Protobuf or Thrift -- nobody says that you actually have to use an IDL, and the serialization format doesn't require it as long as you keep the messages self-describing. Moreover, a lot of effort has gone into making Protobuf (and even Thrift) as efficient as possible -- yet another serialization format is wholly unnecessary.
[Edit] Google even outlines one way to implement self-describing messages using the existing protobuf standard in the project documentation: http://code.google.com/apis/protocolbuffers/docs/techniques....
Other methods including simply encoding fields as tuples of (name, value) -- protobuf includes value types in the field encoding.
Imagine that you add fields/services to a class, without breaking the API. As long as you don't change the ids on your definition, clients with code generated for an old version of the class should still be able to call its services, without serialization/deserialization errors.
Otherwise, you've got to maintain the IDL separately from the service implementation, and keep the two in sync manually. That's a pain, and the bigger your service and/or the more people are involved with developing it the worse the pain gets.
I have three concerns about BERT:
1) It looks like every method in your service code is automatically exposed. That could turn into a security problem. I prefer to explicitly indicate which methods to expose.
2) It looks like your function names have to match the function names exposed by the service. That's fine as a default, but could become a problem over time as the service evolves. Sometimes you want to rewrite the guts without breaking API backward compatibility,
3) I'm not sure how complex the RPC part is; HTTP is plenty capable of sending binary requests and returning binary responses on its own.
One issue that leaps to mind (based on the fact my streaming JSON protocol also travels through Erlang as it happens) is what you do with dicts? Erlang's native representation for dicts is extremely hostile as a term to send to other languages:
Erlang R13B01 (erts-5.7.2) [source] ...etc
Eshell V5.7.2 (abort with ^G)
1> dict:from_list([{"abc", "def"}, {"efg", "hij"}]).
{dict,2,16,16,8,80,48,
{[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[]},
{{[],
[["efg",104,105,106]],
[],[],[],
[["abc",100,101,102]],
[],[],[],[],[],[],[],[],[],[]}}}
That's a hash with two entries, abc -> def and efg -> hij. Note that's the internal representation; dumping out a perl hash gives you a semantic-level representation but under the hood it too has dirty nasty bits like that.If that's not easy, that's a big price to pay for moving binaries around, in general. In specific cases it could be fine.
Doing that automatically means you have to do something else to label it as a key/value list meant to back to a dict.
These are not insurmountable problems, just issues that have to be dealt with. Any problem in Erlang can be solved with another layer of record indirection, but those don't come for free.
I must not have looked closely enough to find the source; I did try.
For a RESTful function call service, each function would be a resource, and the functions would be required not to have side-effects (eg: don't change the state of the service). That's often good design for any API, not just RPC-type services. Again, the exception would be function calls whose purpose is to modify the service state in some way.
When the service state is intended to be different for each user of the service, HTTP has a solution for that too: a cookie which contains a token identifying the session. Any state changes can be associated with the token.
Now you mention bi-directional. If you mean that either side of the interaction can initiate an exchange, then you're right; HTTP is no good for that. Not many RPC services work that way though; it's more complex to design. It's much more common and simpler to have client/server interactions where the client initiates every exchange, and the server listens and responds. You can do a lot with that model.
I can’t agree with such a blanket statement. It completely depends on your goals and application logic. All kinds of protocols/applications are designed to be bi-directional (multiplayer games (think MUDs, FICS, etc.), IRC/Jabber/other chat, VoIP, push email, message queues, multi-user document editors, telnet/SSH, remote device monitoring apps, etc. etc. etc.
Just because such apps aren't so often seen on the web, where their function would have to be hacked on top of HTTP, doesn't mean they aren't common, in general.
Running your multi-player game protocol over HTTP, using cookies to record the session, and polling for updates, just so you can say you’re being RESTful (and "simpler"?) is a terrible terrible idea, because if the semantics of your app stay the same, you basically have equally complex logic, now with several layers of indirection and overhead tossed in for no reason.
> For a RESTful function call service, each function would be a resource, and the functions would be required not to have side-effects
Okay, I want my function call to be "I just captured your queen with my rook, and you'd better find out about it because it's now your turn". How does that work exactly?
For client/client, you're right: HTTP is not appropriate. If you can stomach the XML Jabber (aka XMPP, right?) looked like a good general-purpose bi-directional protocol, and if I'm not mistaken that's what Google Wave is using. If you don't want to pay the XML parsing/serializing overhead, other protocols are available, and maybe that's why BERT-RPC was created. My original point was simply that, depending upon the requirements, the existing HTTP protocol might be sufficient for the kind of interaction needed and it's supported by a rich infrastructure.