Distributed Systems

A single application can often pretend the world is inside one process: call a function, read one database, show an error if something local fails.

A distributed system cannot use that mental model for long. Its useful work crosses boundaries: browser to server, server to database, service to service, or process to process across machines. Once that happens, communication is part of the system's behavior, not a detail hidden below it.

The practical difference is not the number of executables by itself. The difference is that the system must decide what to do when communication is slow, ambiguous, or broken.

Boundary

A design has become distributed when a normal operation depends on a remote boundary:

Boundary New question
Client calls server What if the request times out?
Server calls database What if the database processed the write but the reply was lost?
Service calls service What if a local-looking method call now takes much longer?

These questions are why distributed systems need explicit handling for unreliable networks and latency-aware remote calls.

Design Pressure

The tempting design is to make remote work look like local work:

result = service.process(data)

That shape hides the most important facts. A remote call has a transport, a timeout, a serialization cost, a remote execution cost, and a reply path. Any of those can fail or add delay.

A distributed design is healthier when those costs are visible in the model: commands can be retried safely, messages can be acknowledged, work can be queued, and callers can avoid crossing the network for tiny pieces of data.