Roundtrips, pointers and IDs
... a quick piece about latency and OOP for today.
Remember DCOM?
It was an over-the-network version of Microsoft's COM. It is often brought up as proof that transparent RPC doesn't work: you do want to know whether a call involves a roundtrip via the network or not, otherwise you'll write code that's great when run locally but really really slow in real life.
Which sounds like a tradeoff between API niceness and performance. So, instead of doing something like
Character hero = server.fetchHero(); // here is a network roundtrip
List friends = hero.friends(); // another roundtrip
for (Character c : friends) {
System.out.println(c.getName()); // more roundtrips!
}
We need to something like
CharactersFriendsUglyBlob result = server.fetchHeroAndFriends(); // only network call
List friends = result.friends(); // all these are local calls
for (CharacterWithName c : friends) {
System.out.println(c.getName());
}
... where, in the last version, you only do a roundtrip once, fetch a blob, and process it locally, instead of doing many many roundtrips for each call on each object (like in the first version).
Sadly though, this results in ugly APIs ("give me this hero with their friends but nothing else") and ugly types (... well, whatever this call returns). This the problem GraphQL is supposed to solve... which is great, but... can we do something simpler?
Passing in IDs
So here is the idea. (Partially stolen from Cap'n Proto's "time traveling" RPCs.)
The typical "atomic" RPC call looks like...
Planet homeWorld = hero.homeWorld(); // these are...
String name = homeWorld.getName(); // ... all roundtrips
We pass in some object reference, and we query something about it. But couldn't we just instead:
Id homeWorld;
hero.loadHomeWorldIntoId(homeWorld);
Id planetName;
homeWorld.loadPlanetNameIntoId(planetName);
await(homeWorld, planetName);
The idea being... instead of the server returning a reference / pointer / id of some object, which we then pass back in to query further down the tree, we could just make up an id on our own, and have the server assign a value to it... but this doesn't prevent us from using the id in a subsequent query without waiting for the response from the first request!
The code looks surprisingly similar to classic async-await, with us pretending on the client side that everything is instant... except... our "futures" / "promises" are on the server side! No roundtrips anymore.
We do get the best of two worlds here. There is no longer a need for hand-optimizing query blobs so that we return only the data we actually want in one go... but we don't need a separate language (GraphQL, etc.) either.
... comments welcome, either in email or on the (eventual) Mastodon post on Fosstodon.