Where service boundaries actually crack
Three failure patterns we see when teams draw boxes around modules without naming the data that crosses them.
Most architecture diagrams look tidy until you ask which service is allowed to write a given field. In reviews we run for Content Leafcore clients, the cracks rarely start at the network edge. They start at shared tables, dual-write habits, and “temporary” callbacks that never left.
Shared mutable state
Two services reading the same row is survivable. Two services writing the same row without a single owner is where retries invent ghost states. Name one writer. If you cannot, you do not yet have two services — you have a distributed argument.
The helpful callback
Service A calls B, and B calls A “just for enrichment.” That loop is polite in happy path and vicious when latency spikes. Prefer pushing the enrichment data on the original command, or materializing a read model owned by the consumer.
Error shapes that lie
If every failure returns 500 with a free-text body, clients invent their own recovery folklore. Align error codes with whether the caller should retry, fix input, or escalate. Your future on-call will thank the present you.
When we document these in a backend architecture review, we rank them against the decision the team named — launch date, regulatory deadline, or hire plan — not against an abstract purity score.