I always think of these 2 concepts as Jazz and Orchestral music. This article will try to explain how each work, the pros and cons of using them. I will also use terms in domain driven design, but these patterns are not strictly related to it.
Consider the example of buying a can of Coke from a vending machine. A high level workflow might look something like this:
- Put sufficient amount of coins into the machine
- Select an item
- Provided that Coke is available, the cabinet will then dispatch the item
- Take the item
- Take the change (if any)
Let’s split the vending machine components up into 3 parts:
- Payment — this is where you put some coins in, and in the end it issues the change, or if the process has been cancelled.
- Order placement — user can select an item of choice any given time. It has data about how many of all items are available and the price of items. At code level, think of this component as being backed by the VendingMachine database.
- Cabinet — responsible for dispatching the item that is selected.
In a typical Jazz band, there is no conductor, for some parts, players will improvise other players. This is exactly how each bounded context work together in choreography.
For the above components to have choreography, they would emit an event for every action that was executed on. The architecture would look something like this:
The arrows indicate the events being fired apart from
InsertMoney which is a command user sends to.
In this pattern, each bounded context would register the events they’re interested in. Whenever this event is emitted, the bounded context takes the event and performs certain actions, then emit another event based on the change. Each component only knows about things that they’re interested in.
In an orchestra, a conductor is mandatory, every note of the music for every role in the orchestra is on the conductor’s stand. The music has to be played exactly the way conductor dictates.
This is similar to the orchestration pattern in the sense that typically you would have a process manager (conductor) that handles all incoming events. It would know what to do with every event. It then converts the event to a command and sends it to the relevant bounded context.
With the same example, an orchestration pattern would look something like this:
Orchestrator component is introduced compare to choreography. This component is sometimes also called process manager. It is responsible for all the events from all bounded contexts that are reponsible for a particular scenario. In this case, the whole system. Whenever an event is received, it converts this event to a command and sends the command to the relevant bounded context.
In this pattern, each bounded context now knows nothing about any other. In fact, it doesn’t even need to know about
Orchestrator knows the entire process.
Just by looking at the 2 diagrams, you can immediately tell that there is more process involved with orchestration. Let’s consider adding item availability validation into the system, so it would be between
ItemDispatched. For argument’s sake, cabinet doesn’t do this validation, and it would be a separate bounded context. For choreography, it would be easier to adapt to this business change,
Cabinet just need to unsubscribe
ItemSelected and subscribe to
ItemValidated. But for orchestration, you would need to subscribe to this new event, identify the place between selecting an item and dispatching an item, then call
ValidateItem in the right place.
This benefit of choreography is due to low coupling between each component.
Now consider the slightly less likely scenario where the user has selected an item and that stock validation takes 5 minutes. User selects a can of Coke and 2 minutes later wondering why the can still hasn’t dropped out from the cabinet. How would the system know what the over all status is for a choreography pattern? Since there isn’t a single place for the process, you would have to step through each bounded context and interrogate its status with regards to that can of Coke. It would be much easier for orchestration, because you can just interrogate
Orchestrator for the status.
In reality, whatever the real life scenario your software is modelling, there will be errors. Due to the ease of monitoring for the orchestration pattern, it is easier to identify exactly where the error is, in comparison to choreography.
Of course, there are ways to achieve easier monitoring for choreography. One example would be to have another process that captures all the events and persists them, at least until the process is complete.
In conclusion, one pattern is no better or worse than the other. And you definitely do not have to choose to use one over the other for the entire system. If the business is constantly changing and require you to swiftly adapt to those changes by adding/removing components and not breaking rest of the system, then the low coupling nature of choreography pattern may be more suitable. If the business requires constant update on the status of some long running processes to the users, then orchestration might be the easier thing to implement.