4 ms·
Normally an article would include a summary of the original paper. In this case it may be justified not to do that, but at least a link would have been helpful.
by jerf 5y ago
Normally an article would include a summary of the original paper. In this case it may be justified not to do that, but at least a link would have been helpful. So, first, here's this: https://www.win.tue.nl/~johanl/educ/2II45/2010/Lit/Tanenbaum%20RPC%2088.pdf https://www.win.tue.nl/~johanl/educ/2II45/2010/Lit/Tanenbaum...
Second, to understand the critique I think it's helpful to understand what I would perceive as the chewing on that paper by the community over time, which can be summarized as this: The distinguishing characteristic of an "RPC call", in the sense that Tanenbaum meant, is an attempt to make a network transaction have the exact same semantics as a function call. Importantly, you should read this strictly; the idea isn't that it should be "functionish", or have some syntax sugar around a network transaction that looks a lot like a function in your language, but the idea is that it is providing an abstraction that is fully as reliable as a normal function call within that language, and can, in every way, be treated as a function call. It is a "procedure call" that just happens to be remote, but the abstraction is so complete that you can stop thinking about it entirely as a programmer.
If you add that perspective to a reading of the PDF I linked, you'll probably understand the objections made more deeply.
You now live in a world where Tanenbaum "won", because he is objectively correct that such a thing is simply not possible, so it is much harder to understand what he's banging on about here in 2022. The network "RPC" calls you're used to have backed down the promises they made, and in most languages aren't as simple as a function call. Many modern things that call themselves "RPC" instead focus on having a function-like flow in the happy case, but don't promise to magically make problems with local vs. remote references go away, and instead of jumping through hoops to try to solve the problems just have you deal with them.
I caught the tail end of the RPC world at the beginning of my programmer career. It was a horrible place. You'd have these horrifyingly complex manifests of what the remote RPC call could do, and then they might get compiled into your code like "functions", and then problems as simple as "the remote function call was lost and you never got a reply" would just be a function you called that hung your program forever. Dealing with this was awful and hacky and ugly, because the function abstration they were trying to jam themselves so hard into simply didn't have a place for handling "the function you're trying to call is missing", so you might have to declare "handlers" elsewhere that ran in entirely different contexts or who knows what garbage. Total mess. In the process of trying to make things easier than they could possibly be, they made handling errors incredibly difficult. The sloppiest modern "I vaguely take some JSON and return some other JSON" HTTP API is much preferable to this mess.
One of the interesting lessons of software engineering is that just because something is impossible in general doesn't mean you can't still try, and get something that sorta sometimes works some of the time if all the stars align, and then get people selling that as the next hot thing that is the most important thing in programming ever.
Despite what you may cynically think, I actually don't have any current tech in mind as I type that. It may just be a lack of perspective as I'm as embedded in the present as anyone else, but I don't feel like there's a lot of extant techs right now in the general programming space promising the impossible. Closest I can think of is the machine learning space, but my perception is that it isn't so much that machine learning is promising the impossible as that there are a lot of people who expect it to do the impossible, which isn't quite what I mean. I mean more like people selling database technology that, in order to exist, must completely break the CAP theorem (and I don't just mean shading around the edges and playing math games, but breaking it), or RPCs that fundamentally only work if all 8 fallacies of distributed computing [1] were in fact true, or techs that don't work unless time can be absolutely and completely synchronized between all nodes, and so on. I'm sure there's little bits of those here and there, but there was a time when this sort of impossible RPC was thought of as the future of programming. The software engineering space has become too diverse for things that are essentially fads to take over the whole of it like things could in the 1980s and 1990s.
(See also OO, which also has a similar story where if you learn OO in 2022, you're learning a genteel and tamed OO that has been forced to tone down its promises and adapt to the real world. The OO dogma of the 1980s and 1990s was bad and essentially impossible, and only a faint trace of it remains. Unfortunately, that "faint trace" is still in a few college programs, so it has an outsized effect, but for the most part the real world seems to break new grads of it fairly quickly nowadays.)
Finally, this should be contrasted with the modern answer that is continuing to grow, which is message passing systems. A message passage system loosens the restrictions and offers fewer guarantees, and as such, can do more. You can always layer an RPC system for your convenience on top of a message passing system, but you can't use an RPC system to implement a message passing system with the correct semantics, because the RPC system implements too much. I personally view "RPC", in the looser modern form, as a convenient particular design pattern for message passing, but not as the fundamental abstraction lens you should view your system through. Even the modern genteel form of RPC imposes too many things, because sometimes you need a stream, sometimes you need an RPC, sometimes you just need a best-effort flinging of data, etc. When you have a place you need RPC's guarantees, by all means use an established library for it if you can, but when you need something it can't do, drop it immediately and use the lower-level message bus you should have access to.
[1]: https://www.simpleorientedarchitecture.com/8-fallacies-of-distributed-systems/ https://www.simpleorientedarchitecture.com/8-fallacies-of-di...
- dekhn 5y agoI worked with a system recently that did remote procedure calls. You'd invoke it locally, and it would arrange for the source code of the procedure, the arguments, and the output variables to be pickled and sent to the server. does that truly differ from an x86 executable pushing arguments on a stack and jump/returning to a subroutine?
- Jtsummers 5y agoYes it does. The failure modes are different and so the switch to an RPC from a local call is not transparent. Which is what Tanenbaum discusses in the original paper and this review mostly talks past or restates hut misinterprets. https://www.win.tue.nl/~johanl/educ/2II45/2010/Lit/Tanenbaum%20RPC%2088.pdf https://www.win.tue.nl/~johanl/educ/2II45/2010/Lit/Tanenbaum...
- dekhn 5y agoMany of the things he says in that article bear no resemblance to how problems are solved in the modern era. Nobody other than andrew seems to believe strongly that "transparency" is a required component of procedure calls.
- jacquesm 5y agoEssentially it all boils down to theory vs practice, where the beautiful theoretical concepts fell prey to the various fallacies of distributed computing: https://en.wikipedia.org/wiki/Fallacies_of_distributed_computing https://en.wikipedia.org/wiki/Fallacies_of_distributed_compu... Imo only Erlang really gets this right, and QnX did a halfway decent job of it at the 'OS on bare metal' level. Everything else is just endless duct tape and baling wire.
- jerf 5y agoErlang is so far the only environment I know that took the plunge of expanding the domain of "RPC call" into things that are, technically, local. Thus harmonizing local and remote calls to a much greater degree. Although it's still hard to hide the potential latency differences no matter what you do. This is one of the reasons that even though I'm kinda down on actually using Erlang for a real system, I really recommend any aspiring language designer spend some time with it. Like Haskell, many languages have copied some of its surface aspects, but few languages are capturing its unique deep value proposition. I live without it because on the balance I prefer other things, but what would be even better is having both my later conveniences and capabilities and Erlang's wisdom. I've noodled around with trying to construct a language where the lower guarantees of an RPC call are the default, and you have to "declare" that you want to "cast" an RPC-like API into a static local API, which is then compiler-time checked for being valid to do that with. I haven't got very far beyond the "drool on a napkin" phase for it though.