Leaky Event-Based Microservices’ Integration
When Events are Passive-Aggressive Commands
I worked on a microservices system for a banking client a few years ago and inherited a “Communication” microservice that sends e-mails. Event-based architecture and choreography were all the rage then, so it was applied everywhere, including integration with this microservice.
Event-based integration gives you low coupling, which is a good thing, right? so why not use it everywhere?
It seems the main reason microservices were communicating with this communication microservice via events was to avoid Temporal and Behavioural coupling.
Temporal coupling is when one microservice needs another to be available to carry out a task. Behavioural is when you know which microservice has the capability to perform the action you want.
Based on this, they decided that all microservices should integrate using events, including this communication microservice.
However, there’s an intention by the event producers’ microservices to send an e-mail and an expectation that when these events are published, e-mails will be sent. This makes these events what Martin Fowler calls “Passive-Aggressive Commands.”
“…an event is used as a passive-aggressive command. This happens when the source system expects the recipient to carry out an action, and ought to use a command message to show that intention, but styles the message as an event instead.“
Martin Fowler, What do you mean by “Event-Driven”?
These kinds of events could be tolerated within the boundaries of a microservice, as the ensued implementation coupling is confined to the microservice — where it belongs. However, when used to integrate microservices, it becomes leaky as the communication microservice must know all the events that require an e-mail to be sent.
And since this is a shared microservice, it must know all e-mail triggering events in all the microservices in your system. Additionally, it generally forces events to house all the information required to send those e-mails, resulting in unnecessarily bloated events being broadcasted everywhere.
This current architecture also requires the communication microservice to change whenever a new e-mail triggering event is introduced or whenever e-mails are toggled off for events that previously needed it. This leads to low cohesion and higher coupling, which is the opposite of what a good microservice design should be.
Just because event-based integration gives you low coupling, you should not forget about aiming for high cohesion. It also does not mean you use it everywhere.
“If the only tool you have is a hammer, you tend to see every problem as a nail.” Abraham Maslow.
Evaluate the intentions and purpose of each integration — then consider the impact and the trade-offs in order to make an informed decision. Blanket thinking is never the way to go.
In the below post, I talk about how I’d redesign this integration: