Single Writer Principle
The first important thing to remember while breaking a monolith into microservice is the Single Responsibility Principle (SRP). Any microservice should take care of only one responsibility in a business ecosystem. No other microservice should interfere in another microservices’ responsiblity. In simple terms a microservice should be entirely encapsulated.
When talking about SRP in the context of Event Driven Architecture (EDA) we introduce a new principle which is closely related to SRP called Single Writer Principle. And it states,
Responsibility for propagating events of a specific type is assigned to a single service — Designing Event-Driven Systems by Ben Stopford
Order events should be emitted only by order-microservice and User events should be emitted only by user-microservice. Other microservices can be interested consumers of these events but their interference ends right after reacting to those events. order-microservice should not emit a User event even though it listens to User events and replicates the data in it’s DB. It does so for adding Name of the user in an order or check user status before processing an order.
Advantages of Single Writer Principle
- The team that manages a microservice has full freedom in the schema or versioning of the Entity. Evolution of the entity is not curtailed. If the consumers are interested in the new changes then they can evolve their Domain objects.
- We don’t have to duplicate efforts of analysis or development on another microservice which might emit the same Entity.
- We can publish Final state events to Websockets so that UI can get the final result of an operation by opening a Websocket and receiving events when the flow is complete. Thus Websocket endpoints for a particular entity can reside in the microservice which is it’s Single Writer.
I will explain point 3 in a detailed manner.
Websockets
Imagine you are running a P2P money transfer application where transaction-microservice handles transaction entity (SWP). Following will be the steps happening in an event driven architecture,
- UI sends a POST request to the Rest API of transaction-microservice with From account and To account details along with user-id for Kafka partition-key
- transaction-microservice will handle this COMMAND and push it to Kafka transaction-topic directly after generating a transaction-id
- Now UI starts a Websocket connection to the transaction-microservice and listens to a transaction Websocket endpoint
- Transaction is getting processed by the collaboration of multiple microservices in the mean time
- transaction-microservice when it reaches an End State event like TRANSACTION_FAILED or TRANSACTION_DONE, it sends a message to the websocket with transaction json
- UI websocket client displays the final state when it receives the message after step 5
As our microservice is built on Single Writer principle, all the above business logic can be done in transaction-microservice.
And the most important reason why we adhere to Single Writer Principle is to maintain Backward compatibility. If we allow any service to evolve the schema of an Event, then the schema compatibility can not be maintained. Imagine Order service changing the schema of Payment event and starts writing version 2 events and Payments service defines it’s own version 2. It will be a disaster.
So if you are developing microservices with event driven architecture, follow Single Writer Principle to avoid compatibility issues and give full freedom and power to define, evolve and curate an event to the microservice which owns it.