Why Dependencies Need Both Order and Repair

Kai Nguyen

Hatched by Kai Nguyen

May 19, 2026

10 min read

88%

0

The hidden problem in every system with dependencies

What do a graph algorithm and a distributed transaction pattern have in common? At first glance, almost nothing. One belongs to the neat world of vertices, edges, and linear order. The other lives in the messy reality of microservices, separate databases, and failure. But both are really trying to answer the same uncomfortable question: how do you do things in the right order when the world refuses to stay simple?

That question matters because most systems are not just collections of parts. They are collections of parts with dependencies. A build pipeline depends on tests. A travel booking depends on flights, hotels, and payment. A financial workflow depends on approval, posting, reconciliation, and audit. When these dependencies exist, you cannot treat actions as isolated events. You need a way to express precedence, and you need a way to recover when precedence is broken.

This is where the deeper connection emerges. Topological sort gives us the language of order. Saga gives us the language of repair. Together they describe something most engineering teams understand only halfway: a dependency chain is not just a sequence, it is a commitment structure.


Order is not sequencing, it is dependency management

Topological sort is often taught as a graph trick for interview problems. But its real significance is philosophical. A topological ordering does not merely arrange nodes in a line. It respects a partial ordering that already exists in the system. In other words, it preserves truth about dependency: if A must happen before B, then no clever rearrangement can make B valid before A.

That is why the notion of a source matters. A source, a node with no incoming edges, is not just an algorithmic convenience. It represents an action that is currently unblocked, a step that can safely begin because nothing else must precede it. A sink is the opposite: a node that depends on others but enables nothing downstream. It is a natural endpoint, a result, a closure, a commitment finalized.

This framing is powerful because it replaces the fiction of independent steps with the reality of constrained ones. Consider onboarding a new employee. You cannot assign payroll before identity verification. You cannot provision access before approval. You cannot complete onboarding until the record exists, the manager approves, and the systems have synchronized. There is an order here, but it is not arbitrary. It is embedded in the dependency graph itself.

A dependency graph is not a list of tasks. It is a map of what must be true before other things can become true.

Topological sort helps us find one valid path through that map. But it also reveals something else: the absence of order is not randomness, it is impossibility. If a graph contains a cycle, there is no valid topological ordering. That is a profound warning. It means the system contains circular dependencies that cannot be resolved by sequencing alone.

And that is exactly where many distributed systems fail. They attempt to enforce global consistency through local actions, then discover that the world is no longer a single database, a single transaction, or a single source of truth. The dependencies still exist, but the ability to enforce them atomically does not.


Why distributed systems turn ordering into a failure problem

Microservices make dependency management visible in a painful way. Each service often owns its own data, which means the old comfort of ACID transactions across the whole process disappears. You can no longer say, “Either everything succeeds or nothing happened,” at least not across service boundaries. Instead, business processes become chains of local transactions.

This is where the Saga pattern enters, not as a performance optimization, but as a recognition of reality. If a process spans multiple services, it cannot be treated like a single in-memory operation. It must be decomposed into steps that each succeed or fail locally, with compensation transactions available when later steps break the chain.

That word compensation is crucial. It changes the mental model from “rollback” to “repair.” Rollback implies a hidden global coherence that can simply be restored if anything goes wrong. Repair implies that the system has already moved forward, that some effects are durable, and that the only option is to apply an opposite or balancing action.

Think about booking a vacation. You reserve the flight, then the hotel, then the car rental, then charge the card. If the car rental fails after payment succeeds, you do not get to pretend the earlier steps never happened. Instead, you may cancel the hotel, refund the payment, or offer a different option. That is not a flaw in the process. It is the reality of distributed commitment.

Saga patterns handle this reality in two broad ways. In orchestration, a central coordinator tells each service what to do and in what order. In choreography, services publish events after completing their work, and the next service reacts. These are not just implementation details. They represent two different answers to the question of how order emerges in a system without a global transaction.

Orchestration resembles a topological sort executed by a conductor. Choreography resembles a graph in motion, where each source of completed work creates the conditions for a new source downstream. In both cases, the system is still being arranged according to dependencies. The difference is that now arrangement must coexist with failure.


The deeper synthesis: every dependency graph needs an execution order and a recovery order

Here is the central idea: the real challenge is not finding one correct order, but managing two orders at once.

The first is the execution order, the sequence in which work should happen so that dependencies are respected. This is what topological sort provides. The second is the recovery order, the sequence in which side effects should be undone, compensated, or reconciled when a later step fails. This is what Saga makes explicit.

Most teams think about only the first order. They map dependencies, identify prerequisites, and design workflows. Then they assume failure will be rare or manageable. But in distributed systems, failure is not rare, it is part of the environment. Every network call may time out. Every service may be unavailable. Every message may arrive late, twice, or not at all. A workflow that ignores recovery is not complete, it is optimistic fiction.

A useful mental model is this: topological sort gives you the forward skeleton of a process, and saga gives you the reverse shadow of that process. The skeleton says what must happen before what. The shadow says what must be cleaned up if something breaks after the fact. Together they form a full lifecycle of dependency management.

Imagine a publishing pipeline. Drafting must precede editing, editing must precede legal review, legal review must precede publication, and publication must precede promotion. This is a topological order. But suppose legal review fails after the social team has already scheduled a campaign. Now the system needs a compensation path: unschedule promotion, notify stakeholders, reopen editing, possibly revert the CMS state. The original order alone is insufficient. The workflow also needs a designed sequence for unwinding.

A robust system is not one that never fails. It is one that knows the shape of failure before failure happens.

This is the key connection between the two ideas. Topological sort tells us whether a plan is even possible. Saga tells us how to preserve meaning when that plan partially executes in a world of independent services. One is about feasibility. The other is about durability under failure.

And there is an even deeper insight. In many systems, the recovery path itself is a dependency graph. If you charge a customer after inventory is reserved, then compensation must reverse charge before releasing inventory, or perhaps notify accounting before refunding. The undo steps are not arbitrary. They have their own order constraints, sources, and sinks. In that sense, sagas are not just transactions, they are reverse dependency graphs.


A practical framework: design workflows in three layers

If you want to build systems that handle dependencies well, do not start with tools. Start with a three layer model.

1. Model the dependency graph

First, map the business process as a graph of prerequisites and outcomes. Ask which steps must happen before others, which can happen in parallel, and which steps are terminal. Look for sources, sinks, and hidden cycles.

A source is a step that can begin independently. A sink is a result that depends on prior work and produces no further downstream work. Cycles are warning signs. If A depends on B and B depends on A, then the process may be underspecified, or it may require a different design altogether.

2. Identify the compensation graph

For each step with durable side effects, define what must happen if the workflow later fails. Compensation is not always a perfect inverse. Sometimes you refund, sometimes you notify, sometimes you mark something for manual review. The point is not mathematical symmetry. The point is business symmetry, restoring the system to an acceptable state.

Do not assume every step can be undone cleanly. Some actions are irreversible, like sending an email or initiating an external transfer. For those, define a compensating response instead of pretending rollback exists.

3. Separate control from execution

Decide whether the process is better served by orchestration or choreography.

Use orchestration when:

  • the workflow is complex and business critical
  • you need strong visibility into state transitions
  • compensations must be centrally coordinated
  • debugging and observability matter more than decentralization

Use choreography when:

  • services are loosely coupled
  • the process can evolve incrementally
  • events naturally represent business facts
  • you want fewer central bottlenecks

This is not just a software architecture choice. It is a choice about how much of the dependency graph should be made explicit in one place, and how much should emerge from events across the system.


The real lesson: order without repair is brittle, repair without order is chaos

The temptation in engineering is to choose one virtue and overvalue it. Some teams worship order. They build elaborate pipelines, strict state machines, and carefully enforced dependencies, yet they collapse when a service fails in the middle. Other teams worship resilience. They add retries, fallbacks, and compensations, yet they never fully understand the prerequisite structure, so the system becomes a blur of event handlers and defensive code.

The better path is to treat order and repair as inseparable. Order is how you preserve meaning. Repair is how you preserve continuity. Without order, a system cannot explain why one thing must come before another. Without repair, it cannot survive the moment when the sequence breaks.

This applies far beyond software. Hiring processes, procurement, medical workflows, legal approvals, content publishing, and supply chains all contain dependency graphs. They all face the same dual challenge: they need a valid sequence, and they need a plan for when the sequence is interrupted. The more distributed the system, the more important this becomes.

There is also an organizational lesson here. Teams often talk about “ownership” of services or steps, but ownership without dependency awareness creates silos. A service owner who sees only local success metrics may optimize for the wrong thing. A workflow owner who sees only the overall sequence may underestimate failure modes. The healthiest organizations think in graphs, not in isolated boxes.

A source does not matter because it is simple. It matters because it is a place where motion can begin. A sink does not matter because it is the end. It matters because it tells you where commitments become durable. Between the two lies the real work of systems design: arranging cause, consequence, and recovery so that the whole process remains intelligible even under failure.

Key Takeaways

  1. Model processes as dependency graphs, not just task lists. Ask what must happen before what, and identify sources, sinks, and cycles.
  2. Design compensation alongside execution. Every durable side effect should have a planned response if the workflow fails later.
  3. Treat orchestration and choreography as control strategies, not just architecture styles. Choose based on visibility, complexity, and coupling.
  4. Assume recovery is itself ordered. Compensation steps often depend on one another and should be designed as a reverse workflow.
  5. Use cycles as a warning signal. If your process has circular dependencies, you likely need redesign, not just better tooling.

The most important shift is this: do not ask only, “What is the correct order?” Ask instead, “What is the order of commitment, and what is the order of repair?” Once you see systems this way, topological sort stops being a classroom algorithm and Saga stops being a microservices pattern. They become two halves of a larger discipline: making dependency manageable in a world where certainty ends at the boundary of your system.

In that sense, the best-designed workflows are not those that never encounter failure. They are the ones that can still tell a coherent story when failure arrives halfway through the sentence.

Sources

← Back to Library

Hatch New Ideas with Glasp AI 🐣

Glasp AI allows you to hatch new ideas based on your curated content. Let's curate and create with Glasp AI :)

Start Hatching 🐣