Guide

Data through databases and services

Data must be encoded whenever it leaves a process. Compatibility is always between the process that encodes and the one that decodes.

Data outlives code

In a database, the writer encodes and a reader decodes later. That reader may be newer code, so you need backward compatibility. During a rolling upgrade it may also be older code, so you need forward compatibility too. Code changes in minutes, but old rows keep their old encoding for years. Rewriting all of them is costly, so databases avoid it: a new nullable column is filled with null when read. A full snapshot is a good time to write every row in the latest schema.

Services and REST

A service offers a fixed API over the network, not open queries. A web service is reached over HTTP. REST uses HTTP's own ideas: URLs name resources, and HTTP handles caching and login. APIs are described with OpenAPI (for JSON) or protobuf (for gRPC), which can generate docs and client libraries.

Why RPC is not a local call

RPC tries to make a remote call look like a local one. But a network call can be lost or time out, and then you do not know if it ran. A retry may run it twice unless each request has a unique ID. Delays vary wildly, and every argument must be encoded as bytes.

Load balancing and discovery

Clients must find a healthy instance. A load balancer gives them one address. DNS gives many IPs but caches them. A registry tracks live instances by heartbeat. A service mesh puts a balancer beside every app.

Evolving service APIs

Servers usually upgrade first. So requests need backward compatibility and responses need forward compatibility. Public APIs may need old and new versions running side by side.

Remember

  • Data outlives code, so a database needs both kinds of compatibility.
  • A service is a fixed API; REST builds on HTTP.
  • A timeout means "unknown", and retries need unique IDs.
  • DNS caching makes it slow for fast-changing instances.
  • Servers first: backward on requests, forward on responses.