I started very recently at a company that uses a rather unusual custom framework for their web applications, at least compared to the typical web application frameworks I know. Instead of a RESTful webservice an RPC mechanism is used to communicate with the server.
Communicating with the server looks like a simple function call, but the function is executed on the server, not the client. On the server-side there is a way to define which functions the client can call. The details of how this is translated into http requests is abstracted away completely.
I've only used this a short time now, but it seems pretty convenient. But I'm wondering what drawbacks of this approach I'm missing. Everyone else seems to be doing it differently, which usually is a sign for me that I might be doing something stupid or brilliant, with much higher odds on the former.
Best Answer
REST was designed for the web, and the web was designed for REST. The two just fit will together. Roy Fielding's 2000 PhD thesis Architectural Styles and the Design of Network-based Software Architectures defined and introduced the term REST, and there is significant interplay between the web and REST: Roy Fielding worked on HTTP/1.1, of which he is the primary author, and he used what he learned there to describe REST in his dissertation.
So, the simple reason why the web and REST go so well together is that the definition of REST was extracted from how the web works, and the web is an implementation of REST.
That's why REST is a good fit for web services and web apps: because you simply do the same things that have already been proven to work in the "human" web, and apply them to the "machine" web.
The big problem with RPC (depending on the exact implementation) lies basically in the Fallacies of Distributed Computing, which are explained in more detail in this whitepaper by Arnon Rotem-Gal-Oz:
These are all assumptions that newcomers typically make when they start to create distributed systems. Of course, all of them are false. And you need to take all of them into account when creating distributed systems.
The problem with many RPC implementations is that they try to make remote calls look like local calls. But they are nothing alike:
a
and thenb
, I get back the result ofa
and then the result ofb
– this is just a more general version of the previous point, with RPC, you may get any of the two answers 0 or more times in any orderYou will have to deal with all of the above for a remote call. But if your framework makes remote calls indistinguishable from local calls, then you can't, because you don't know which ones are the remote calls. The framework may try and handle all of those for you, but the problem is: the framework doesn't know as much about your system as you do. It doesn't know whether there are calls where it actually doesn't matter if one gets lost once in a while. So, the framework has to be very defensive, and that is expensive in terms of latency and bandwidth.
Especially since the framework actually cannot shield you. The CAP Theorem says that a distributed system cannot be Consistent, Available, and Partition-Tolerant at the same time; more precisely, it says that once a Partition occurs, the system cannot continue to be both Consistent and Available, it has to choose one (contrary to popular belief, the theorem does not say that you cannot have all three, when the system is running normally, you can have all three; but once you have a Partition, you have to choose one of the other two). The PACELC Theorem extends the CAP Theorem by showing that even when the system is working, you have to trade-off Latency vs. Consistency.
These are important trade-offs that the framework pretty much cannot shield you from, since they are domain-specific and important to the core design.
Contrast this with an approach like Erlang's, which does work: in Erlang, all message sends are treated as remote, even if they are local. This means you always are prepared to deal with all of the above problems (and many more). For local processes, these do pose a little bit of an overhead, though. In order to help with this, there are great deal of tools, frameworks, libraries, patterns, and idioms for dealing with error handling and supervision.
You haven't described how your RPC framework works in particular, and what language or libraries you are using, but I have a strong suspicion that it belongs to the former "pretend the network doesn't exist" type. Those just don't work. It is okay to remove the distinction between local and remote calls by treating everything as a remote call. Doing it the other way around abstracts too much: the network is part of your system, if you abstract it away, you abstract away something that you actually need to know about.
Now, whether you have to specifically use REST or not, that's an entirely different question. As I explained above, the web was designed for REST and REST was designed for the web, so the two do make sense together, but you can use other architectural styles, if you want to. But at least part of your question was about "why not RPC", and I laid out the reasons above, more precisely I explained why the type of RPC I suspect you are using may land you in trouble.