What?

In the orchestration model, a central coordinator is introduced. This service is tasked with directing the application flow and carries the responsibility for the core business logic. This paradigm naturally follows a request-response logic.

Choreography, however, operates on a different plane. Each service acts largely independently, loosely coupled and connected to others only by shared events. This is the event driven paradigm. Systems like Untitled, for example, naturally inherit this logic, making choreography quite popular. Still, it’s worth noting it isn’t always the optimal choice.

Generally speaking, it’s observed that orchestration is often preferable within the confined scope of a single microservice, while choreography is a more robust mechanism for communication between these bounded contexts.

Trade-offs

Choosing one approach inevitably brings compromises.

For choreography, the primary friction points include:

  • End-to-end monitoring becomes complex; tracking a single transaction through an entire chain of events isn’t straightforward.
  • Implementing precise timeouts is difficult, even brutal, given the temporal decoupling.
  • The order flow is not explicitly defined; no property “naturally emerges” to describe what the system does as a whole. The entire process relies on the implicit mental model of the person who conceived (or has to understand) the complete end-to-end system.

On the orchestration side, the main concerns are:

  • The transaction costs introduced by the centralized coordinator.
  • The need to learn and manage specific coordination services (e.g., a new AWS service).

It is important to emphasize that adopting orchestration doesn’t mean abandoning the benefits of event-driven architecture entirely. One can still publish events as useful artifacts within an orchestrated flow. This allows us to decouple, say, the order flow from other functionalities that need to react to those order-related events.

Hybrid approach

..where should one draw the line?

A bounded context is a well-defined area of a system with a specific responsibility (e.g., “order management”). It is within this functionality that the orchestration approach is generally advised: components work cohesively to achieve a precise goal.

graph TD
    subgraph bounded context
        A[order service] --> B(step function);
        B --> C[payment service: request payment];
        C --> B;
        B -- success --> D[inventory service: reserve Stock];
        D --> B;
        B -- success --> E[shipping service: sreate shipment];
        E --> B;
        B -- success --> F[order service: update status];
        B -- failure --> G[compensating action: refund payment];
    end

The benefit of this delineation is that the context is small and well-organized enough to be understood and managed by the entire team, including new members.

Using choreography inside a bounded context is highly problematic in practice. If every function only communicates via events (SNS/EventBridge) without a global flow view, an implicit workflow is created. It emerges as the sum of interactions but isn’t explicitly modeled. This makes it difficult to reason about, hard to monitor, and especially challenging to debug. choreography is ideal between differbent ounded contexts.