Building a dependency map: critical vs optional
coreintermediateA dependency map is an explicit, drawn-out record of every other service, database, queue and third-party API a service calls, in one place — most teams have this knowledge scattered across individual engineers' heads rather than written down, which means nobody can answer "what breaks if the recommendations service goes down" without guessing. Once the map exists, the next step is classifying each edge as critical or optional: a critical dependency is one whose failure means the calling service cannot do its primary job at all (a checkout service cannot function without the payment gateway), while an optional dependency is one whose failure should degrade the experience but not break it (a product page can render without the recommendations service, just without the "customers also bought" section). This distinction is not obvious from the code alone — a synchronous, blocking call to the recommendations service looks identical in the code to a synchronous, blocking call to the payment gateway, even though one failure is catastrophic and the other should be invisible to the end user. Making the classification explicit is what tells an engineer which calls need a fallback and which calls genuinely justify blocking the whole request.
Think of it as
A dependency map is like a building's utility diagram: it shows exactly which pipes and wires actually feed which room, drawn out once by an electrician rather than reconstructed from memory during an outage. Critical vs optional is the difference between the wire that powers the emergency lighting (the building genuinely cannot be occupied without it — critical) and the wire that powers the decorative fountain in the lobby (nice to have, and the building operates completely fine without it — optional). A fire inspector does not need to guess which is which during an actual fire; the diagram already says so, and a well-run building maintains it as circuits change, not just draws it once at construction and forgets it.
What we're doing: Classify five downstream calls a checkout service makes.
- 2
- Critical: without a successful charge, there is no purchase — there is no reasonable fallback that lets checkout "succeed" without payment actually happening.
- 3
- Critical: if stock cannot be confirmed and reserved, the order should not be accepted — allowing it anyway risks selling inventory that does not exist.
- 4
- Optional: an upsell suggestion is a nice-to-have on the confirmation page; if the call fails or times out, the page renders without it and the purchase proceeds normally.
- 5
- Optional: points can be awarded on a short delay via a retry queue if the loyalty service is briefly down — no user-visible impact to checkout itself.
- 6
- Optional, and further, should not even be a blocking call at all — an analytics event is fire-and-forget, and a checkout that fails because the analytics pipeline was slow is a design bug, not an acceptable trade-off.
Why this works: The five calls look interchangeable in code — five function calls inside the same request handler — but only two of them are actually critical; treating all five as equally blocking (the default when nobody has done this classification) means an analytics outage can take down checkout, which is a self-inflicted failure with no corresponding benefit.
Writing every downstream call as synchronous and blocking by default
Wrong
Better
What you see: A brief outage in the recommendations service, which no one classified as critical, causes every checkout attempt to time out and fail, and the incident review discovers the outage never should have been able to touch checkout at all.
Why: Writing a downstream call is the same one line of code whether the dependency is critical or optional — nothing in the syntax forces a developer to decide, so without an explicit classification step, every new integration defaults to synchronous-and-blocking simply because that is the easiest way to write it, regardless of whether the dependency actually deserves that level of coupling.
- Payment gateway: Critical, High blast radius — checkout cannot complete without it
- Inventory service: Critical, High blast radius — cannot confirm stock
- Recommendations: Optional, Low blast radius — hide the section on failure
- Loyalty points: Optional, between Low blast radius and High blast radius — award asynchronously, retry later
- Analytics pipeline: Optional, Low blast radius — fire-and-forget, never blocks the request
Classifying a dependency: the test that decides critical vs optional
Remember: A dependency map is an explicit, maintained inventory of every downstream call a service makes; classifying each one as critical (failure breaks the primary function, no reasonable fallback) or optional (failure degrades gracefully) is a deliberate design decision that the code itself does not make for you — an unclassified dependency defaults to synchronous and blocking, which quietly turns every dependency into a critical one whether it deserves that or not.
See also: preventing cascading failures via decoupling · the failure mode question checklist · why circuit breakers exist

