Orchestration
A coordination pattern where a central component controls the flow of a distributed process by sending commands and reacting to events.
In orchestration, a central component controls the entire flow. It knows the steps of the process, sends commands to each participant, and reacts to the results. If something fails, the orchestrator decides what to do next: retry, compensate, or abort.
This is the opposite of choreography, where services react to events independently and the flow emerges from the chain of reactions. With orchestration, the logic is in one place. You can open the orchestrator's code and read the whole process top to bottom.
The most common implementations of orchestration in distributed systems are the saga and the process manager. A saga coordinates compensating actions across services. A process manager goes further: it maintains state, tracks which steps have completed, and handles branching logic.
Orchestration is not limited to distributed systems. In Clean Architecture, the application layer plays the role of an orchestrator for the write side of your application. A command handler loads an aggregate, calls domain methods, publishes events, and saves the result. The business logic stays in the domain layer while the application layer handles the coordination.
The tradeoff is coupling. The orchestrator depends on every participant in the process. When you add a new step, you change the orchestrator. In choreography, adding a new step means deploying a new subscriber that reacts to an existing event, without touching any other service.
Start with choreography for simple flows where each step naturally follows from the previous event. Move to orchestration when the process has branching logic, multiple conditional paths, or compensation requirements that need to happen in a specific order. The complexity of maintaining a central coordinator pays off when the alternative is chasing a workflow across a dozen services.
References
- Combining DDD, CQRS, and Clean Architecture in Go — Dedicates a section to orchestrating with commands. The application layer becomes responsible only for orchestration of the flow, while business logic stays in the domain layer.
- How to implement Clean Architecture in Go (Golang) — Describes the application layer as an orchestrator that glues other layers together. If you read the application code and can't tell what database it uses, it's a good sign.
- Microservices test architecture. Can you sleep well without end-to-end tests? — Discusses testing orchestration in the application layer. The application layer is the right place for orchestration: calling adapters and services in a particular order and passing return values around.
- Database Transactions in Go with Layered Architecture — Shows how splitting repositories per table leads to application logic orchestrating them. Explains why this split often has no practical value and how to design better boundaries.
- Shipping an AI Agent that Lies to Production: Lessons Learned — Notes that most complexity in AI agents is in the orchestration. The agent-orchestrating code is your domain logic, and all well-known patterns and good practices still apply.
- Event-Driven Architecture: The Hard Parts — Discusses orchestration in the context of sagas and distributed transactions. Covers when orchestrating a flow across services adds unnecessary complexity and when merging services is the better choice.
- Is Clean Architecture Overengineering? — Explains that with a separate domain layer, the application layer becomes mostly orchestration. Testing it separately often doesn't add value because component tests already cover the full flow.
- How to Know If your Software Is Overcomplicated or Oversimplified? — References the application layer as orchestration code in the context of deciding how many architectural layers a project needs.