3 ms·
> Making a server call from the client was transparent. It looked like any other function call That is a very bad idea and one of the reasons this kind of thin
by brazzy 3y ago
> Making a server call from the client was transparent. It looked like any other function call
That is a very bad idea and one of the reasons this kind of thing rightfully died out.
Because a server call isn't like any other function call. It has orders of magnitude higher latency, and additional failure modes that you actually have to take care of.
It shouldn't look like any other function call.
- lelanthran 3y ago> That is a very bad idea and one of the reasons this kind of thing rightfully died out. I agree, but, like everything else that is a bad idea, naming conventions help.[1] Namespacing helped too. I used naming conventions to ensure that network calls looked different, and namespaces that kept network objects in their own module. [1] Right now we rely on naming conventions in most codebases to differentiate between #define'd literals and variables (C), between constants and variables (Java), between variables and methods (Kotlin, Java, everything else), between interfaces and classes (C#, C++, everything else too, probably), for everything in Python (pep8). Using naming conventions to identify remote calls is no different than using naming conventions to identify interfaces.
- stickfigure 3y ago> It shouldn't look like any other function call. I'm sorry, This is the stupidest thing I see commonly repeated in public discourse about software. Every single distributed application I've ever worked on in my 30-year career (including working for multiple companies you've heard of) wrapped remote calls in something that looks like a normal function call. It doesn't matter if your low-level RPC stub throws RemoteException or returns RemoteError, somewhere up the call stack someone has wrapped this into a simple method that looks like this: doSomethingUseful(); In real life, you make a call to a function and you live with the consequences. If you're lucky, the docs let you know the performance and failure characteristics. If not, you make some assumptions. When those assumptions are wrong, you spend some time debugging and profiling. Adding a bunch of syntactic noise to the callsite doesn't help. The first thing any competent programmer will do is abstract your noise away in convenience methods. Because 99% of the time, it doesn't matter that your call is remote. Take a look at your own codebase that makes client REST calls to some other service - you may hand-wire a bunch of http calls, but somewhere up the stack there's a function that hides the http mess. Everything below that function is accidental complexity.
- naasking 3y ago> Every single distributed application I've ever worked on in my 30-year career (including working for multiple companies you've heard of) wrapped remote calls in something that looks like a normal function call. This isn't a problem as long as the returned value provides the right failure semantics (like futures). The problem with trying to encapsulate the network is that deep call chains lead to cascading failures for problems that are common in networks (partitions, latency, etc.). These failure modes also lead to more pervasive use of timeouts in deep call chains, which then introduces non-determinism, which itself makes issues impossible to debug.
- stickfigure 3y agoThis is also nonsense. 99% of the time these failure modes are irrelevant. A remote call fails, the error propagates up the call stack, and someone gets an error message. Just like any of the thousands of other things that can produce errors in complex systems. In the rare case you need to harden a particular call, you add caching or retries or whatever other logic fits your use case. It matters not one bit whether you're using futures or synchronous rpc stubs. Actually it does - synchronous code is easier to harden because it's easier to reason about. Even javascript added await because it's better to pretend that async code looks synchronous. The failure semantics of "throws an exception" are just fine.
- naasking 3y ago> A remote call fails, the error propagates up the call stack, and someone gets an error message. Uh-huh, but did the message actually get through? Can they safely just retry? These are very uncommon failure modes on local systems but very common on networked systems. Without a proper stateful abstraction beyond just "procedure call", like a promise, you can't address these failure modes properly. > In the rare case you need to harden a particular call, you add caching or retries or whatever other logic fits your use case Which now makes your system nondeterministic like I said. > Even javascript added await because it's better to pretend that async code looks synchronous Yes, linear code is easier to read. I don't see what this has to do with anything. The use of promises and await indicates a possibility of failure semantics that would otherwise not be apparent in the program's control-flow. Yes, you can superficially make this look like synchronous code, but it's not synchronous code.