5.10 Decision cheat sheet
Ask both directions separately. Can new code read old data? (backward) Can old code read new data? (forward) A change is only safe if the answer to both is yes for the duration of…
Which encoding?
| Situation | Choose |
|---|---|
| Public API, cross-organization, must be debuggable | JSON + OpenAPI |
| Internal service-to-service, high volume, typed languages | Protobuf + gRPC |
| Streaming/analytics, many records per file, schemas generated from data | Avro + schema registry |
| Columnar analytics files | Parquet |
| Anything at all | Never a language-native format |
Is this change safe? Ask both directions separately. Can new code read old data? (backward) Can old code read new data? (forward) A change is only safe if the answer to both is yes for the duration of your rolling upgrade window — which, for public APIs, may be indefinite.
Protobuf or Avro? Protobuf when the reader shouldn't need the writer's schema (RPC, self-contained messages) and schemas are hand-authored. Avro when schemas are dynamically generated or there's one schema per file/topic, and you're willing to run a registry.
RPC or messaging? RPC when the caller needs the answer now and the callee's availability is acceptable. Messaging when you want buffering, redelivery, fan-out, and decoupling — and can tolerate asynchrony.
How do I version a public API? Pick one mechanism (URL path is the least surprising), instrument usage per version and per client from day one, publish a deprecation policy, and expect to run old versions far longer than you planned.
Do I need durable execution? Only when a multi-step process spans services or third parties and partial completion is unacceptable. Otherwise a retry with an idempotency key is simpler and less brittle. If you adopt it, commit to determinism and to versioning-by-deployment.