# Why I Orient Events to their Producer

# Context

Event-Driven Architecture is an evolution of a more generic Microservices Architecture. With Microservice Architecture, responsibility is bound within defined domain boundaries and each service takes full ownership of its domain. Ideally, no business operation would span across services and every task would fall neatly into a single microservices domain. Of course, the reality is more complicated and microservices must interact to accomplish any business operation. How they communicate becomes a paramount consideration and is exactly what Event-Driven Architecture addresses.

# Working Example

Consider the simple e-commerce example; Our company Widgets Inc. has a backend composed of an **Order Service**, **Inventory Service** and **Email Service**. When a Customer places an *Order* the **Order Service** must record the details of the *Order*, the **Inventory Service** needs to reflect the change in inventory and the **Email Service** must notify the *Customer* of their *Order* status. Fundamentally, the operations necessary from each service are well defined by the business; it's the degree of coupling among them we can control.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1672239684473/c69146c1-8f9f-4744-8f46-1a5a7323eaad.png align="center")

# Communicating

Great communication yields a resilient system and great communication is all about the degree of *Coupling*. When microservices work together they will need to communicate with one another. As microservices evolve independently from one another, communication between them requires deeper decoupling.

## Tight and Dependant - Synchronous

In a synchronous approach, services directly call http endpoints in a request/response model. This tightly couples the system together and can lead to cascading failure. Further, this approach can yield a distributed monolith, brittle and difficult to operate, all the benefits of microservices are lost.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1672239694619/abffce5c-d046-43dd-88b8-22cae26fb717.png align="center")

## Ball Room Dancing - Orchestration

A slightly more asynchronous approach is to [Orchestrate](https://en.wikipedia.org/wiki/Orchestration_(computing)) or [Choreograph](https://en.wikipedia.org/wiki/Service_choreography) services within a workflow. In this approach, it's common to introduce an **Orchestrator**. An **Orchestrator** is responsible for coordinating the workflow and, if necessary, executing compensation upon failure. Here the services are only coupled to the **Orchestrator** while the **Orchestrator** is ***coupled*** to all participating services. This variation of tight coupling is due to treating this business operation as a ***Distributed Transaction***.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1672239705227/4c6cf2cd-e345-439e-a67d-321bb6a034e5.png align="center")

I'll place *Distributed Transactions, Orchestration vs Choreography* out of the scope of this post but each yield varying tradeoffs.

# Consider the Events

In both our Synchronous and Asynchronous variations, our Events can be viewed as commands with implicit knowledge of the Workflow and the Consumer of the command.

## Bad Messages

For example, this might be our associated Message Schemas:

```apache
message PlaceOrder {
  string MessageId = 1;
  string ProductId = 2;
  int32 Count = 3;
}

message UpdateInventory {
  string MessageId = 1;
  string ProductId = 2;
  int32 Count = 3;
}

message NotifyCustomer {
  string MessageId = 1;
  string CustomerId = 2;
  string Status = 3;
}
```

Each *Message* is imperative and directs a *Consumer* to take action. Whether these messages are communicated Synchronously or Asynchronously is irrelevant. Within these messages lies the knowledge of ***What & When*** to execute particular functions. This becomes a brittle distributed mess because each service must be oriented to execute within a predefined workflow there's no room for changes or discrete failure.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1672239722115/2a7d4bc8-bdf3-4e95-9661-2afebfb99406.png align="center")

Commands by their very nature mean the command source knows what must be done next. Whether it's an **Orchestrator** or the services are Choreographed, commanding one another spreads ***Knowledge*** where it shouldn't be. For example, within `NotifyCustomer` there's a string representing `Status` but exactly which domain understands `Status`?

## Better Approach

What we must recognize is that ***Producers*** are discrete domains and we shouldn't muddy those separations. ***Events*** should reflect the perspective of the originating domain. This means that a single domain can only speak for itself. We won't let the **Order Service** command the **Inventory Service**. Neither will we need an **Orchestrator** to command our domains.

```apache
message PlaceOrder {
  string MessageId = 1;
  string ProductId = 2;
  int32 Count = 3;
}

message OrderPlaced {
  string MessageId = 1;
  string CausationId = 2;
  string ProductId = 3;
  int32 Count = 4;
}

message InventoryUpdated {
  string MessageId = 1;
  string CausationId = 2;
  string ProductId = 3;
  int32 Count = 4;
}
```

Now we speak in the past tense after the *Order* is placed. Each domain simply states its domain knowledge. The **Order Service** can only say the *Order* is placed, it cannot tell anyone to update their inventory. It's the responsibility of the **Inventory Service** to know what to do when an *Order* is placed. Finally, our **Email Service** knows that the *Order* is placed and inventory is updated indicating a predefined *Customer* notification.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1672241170825/bf450f30-727b-4d8b-932a-1e25915b316f.png align="center")

More than simply a semantic argument, the underlying intention is to maintain domain integrity and service independence. The common contrary argument is that the state is more difficult to ascertain with this approach. Certainly a valid perspective, however, the state of any system is simply the aggregate of Events and can be known precisely via `Message` & `Causation` Ids.

# TL;DR

> Events should reflect the perspective of the Producer and not implicitly dictate the Events' Consumption.
