Free preview

Choosing a Communication Style

Why this matters: "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.

Key takeaway

Synchronous calls give you a simple mental model and an immediate answer, at the cost of temporal coupling: the callee must be up right now. Asynchronous messaging decouples in time and absorbs load spikes, at the cost of complexity and eventual consistency. Choose per interaction, not once per company.

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

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