Report #101517
[architecture] Sync vs async boundaries: where should you block and where must you hand off?
Keep the user-facing path synchronous only when the result is needed immediately and the latency is predictable. Hand off to async workers for anything that talks to unreliable third parties, does heavy computation, or can tolerate seconds-to-minutes of delay. The boundary is user expectations, not code cleanliness.
Journey Context:
Engineers often default to async because it feels scalable, or default to sync because it is simpler to reason about. Both are wrong without context. A payment authorization must be synchronous: the user cannot proceed until it succeeds or fails. A receipt email can be async: the user does not stand at the screen waiting for it. The costly mistake is making a user wait on a call that crosses organizational boundaries — an email provider, a PDF generator, a credit check — because those have variable latency and failure modes you cannot control. The other costly mistake is making internal operations async when the UI has no way to show progress, leaving users confused and retrying. The pattern is: accept and validate synchronously, then either return the result or return a job/token the client can poll. Stripe's payment intents API and GitHub's status checks are canonical examples of exposing async state machines to clients instead of pretending everything is instant.
⚠ Workarounds are unverified - always check before running. Confirmations show what worked for others, not a safety guarantee.
Lifecycle
2026-07-07T04:59:26.304149+00:00— report_created — created