A library you depend on is something you maintain. A service you call at runtime is something else entirely: you have taken on its availability as a component of your own. If your request path makes a synchronous call to something you don’t operate, then whenever that thing is down, unless you’ve done something deliberate about it, you are down too. The dependency isn’t just a maintenance obligation anymore — it’s an operational one, and it’s live every second rather than once per upgrade.

The arithmetic is worth doing explicitly because intuition understates it. If a request touches four services that are each up 99.9% of the time, and any one failing means the request fails, your composed availability is roughly 99.6% — you’ve turned about nine hours of annual downtime into more than thirty. Nobody chose that number; it emerged from four separate reasonable-seeming decisions to call something over the network. Each addition looked small in isolation. The failure rates multiply anyway, and the total is a property of the architecture that no individual team is watching.

What breaks this arithmetic — in the good direction — is refusing to inherit the failure. A call whose result isn’t essential to the response can have a timeout and a fallback: return the page without the recommendations, serve the last known value, degrade the feature rather than the request. A call that doesn’t need to be synchronous at all can become a queued message, which converts “they’re down so I’m down” into “they’re down so this is delayed.” Each of these decouples your availability from theirs, and the choice of which pattern applies is per-call and specific: what does this response actually require to be correct, versus what merely makes it better?

The failure mode people underestimate isn’t the clean outage — it’s the slow dependency. A service that’s returning errors fast is almost benign; you notice immediately, the circuit opens, the fallback runs. A service that has become slow but still answers is far worse, because your requests pile up waiting on it, holding connections and threads, until your own capacity is exhausted and you fail for reasons that have nothing to do with the original call. That’s how one degraded dependency takes down systems that don’t even depend on it directly. Timeouts, bounded concurrency per dependency, and circuit breakers exist for exactly this: to make someone else’s slowness bounce off you instead of accumulating inside you.

The through-line with the maintenance side is the same: dependencies are priced too cheaply at the moment they’re added, because their cost arrives later and diffused. Adding a runtime call is one line and it works immediately in testing, where the other service is always up and always fast. Its real cost is a permanent tie between their operational quality and yours, paid on their worst day rather than on the day you wrote the line. It’s worth knowing, for each external call in your critical path, what happens when it hangs — and if the honest answer is “we’ve never checked,” that’s not a dependency you’ve evaluated. It’s one you’ve inherited.