Free preview

Choosing a Communication Style

In one line: "we'll use gRPC" answers the wrong question. The decision that shapes your architecture is synchronous or asynchronous — whether the caller waits. Protocol comes second.

The fundamental split

A useful test: would a human wait for this? Checking out needs the payment authorized before the page can respond — synchronous. Sending the receipt email, updating the recommendation model, and refreshing the analytics rollup do not — asynchronous, every one.

The four options

StyleShapeStrengthsWeaknessesReach for it when
gRPCSync, binary, HTTP/2Fast, typed contract, streaming, small payloadsNot browser-native, harder to eyeball on the wireInternal service-to-service at volume
REST / HTTP+JSONSync, text, HTTP/1.1+Universal, cacheable, trivially debuggableVerbose, over- and under-fetching, no schema by defaultPublic APIs, partner integrations, browser clients
GraphQLSync, client-specified queryClient fetches exactly what it needs in one round tripServer complexity, caching is hard, N+1 queriesMany diverse clients over one rich data graph
Messaging / eventsAsync via a brokerDecoupled, buffers spikes, multiple consumers, replayableEventual consistency, ordering and duplicate handlingFan-out, background work, spike absorption, audit trails

Why asynchronous changes the failure story

A queue converts a hard failure into a delay. If the recommendation service is down, synchronous calls fail and users see an error. With a queue, messages accumulate and drain when it recovers — the user never notices.

This also inverts the dependency direction. Checkout does not know its consumers exist. Adding a fourth consumer requires no change to checkout at all — which is the real reason event-driven architectures scale organizationally, not just technically.

The trade you are actually making

ConcernSynchronous RPCAsynchronous messaging
Latency to answerImmediateEventual — could be ms or minutes
Failure visibilityInstant and obviousDeferred — needs dead-letter queues and monitoring
Load spikesPassed straight through to the calleeAbsorbed by the broker
DebuggingOne stack trace, one trace IDDistributed tracing required to follow the chain
ConsistencyEasier to keep strongEventual by construction
CouplingTemporal — callee must be up nowDecoupled in time and in knowledge

Asynchronous is not free

Going async does not delete complexity, it relocates it. You now own duplicate handling (brokers deliver at-least-once — Lesson 4 applies unchanged), out-of-order arrival, poison messages, dead-letter queues, and consumer lag. Teams that adopt events to "simplify" and skip that machinery end up with silent data loss instead of loud errors.

A practical decision rule

  • The caller needs the result to respond → synchronous. Internal and high volume → gRPC; external or browser-facing → REST.
  • Many clients, each needing a different slice of a rich graph → GraphQL at the edge, gRPC behind it.
  • The work can happen later, or more than one system cares → events.
  • The work is slow, bursty, or retriable → queue it, and return an ID the client can poll.

Key takeaway

Default to synchronous for the read path (a user is waiting) and asynchronous for the write side effects (nobody is). Most well-factored systems are a synchronous shell around an asynchronous interior.

Interview signal by level

LevelWhat a strong answer sounds like
L4Picks a protocol and moves on: "REST between services."
L5Splits the paths: "synchronous for checkout, but email and analytics go on a queue so they can't take checkout down."
Staff+Quantifies the coupling: "each synchronous dependency multiplies into my availability, so I'd keep the critical path to two calls and push the rest to events — accepting eventual consistency, and here's the dead-letter and lag monitoring that requires."

Next: once writes are asynchronous, what is a read allowed to return?

Enjoying the preview?

Create a free account to unlock the rest of this course, the in-browser judge, and live AI mock interviews.

Sign up free to continue