Events-first domain-driven design (DDD) and event streaming are critical in a microservices based architecture, said Jonas Bonér, founder and CTO of Lightbend, who spoke at the QCon New York 2018 Conference last week about using events-first design to create a resilient and scalable architecture.
He stated that when you start with a microservices journey you should take care not to end up with "microliths" because you may bring bad habbits from monolithic design to microservices, which creates a strong coupling between services. A DDD approach without the events-first perspective can easily lead you down the wrong path. You shouldn't focus on things (the Nouns, like domain objects) but instead focus on what happens in the system (the Verbs, like events).
A microservice architecture based on events and commands helps with resilience, scalability, traceability, and loose coupling in the system. Events represent facts of information about something that has happened in the past (for example, OrderCreated
, ProductShipped
). Events can be disregarded but they cannot be retracted or deleted. Also, new events/facts arrive in the system that can invalidate the existing facts. Commands, on the other hand, are the object form of a method/action. They are imperative. Examples of commands are CreateOrder
and ShipProduct
.
Bonér suggested that we use the events to define bounded contexts in the system. Event-driven services receive and react to facts that are coming their way and then publish new facts to other services in the system. He also talked about the Aggregate design pattern which is used to maintain integrity and consistency of the domain data. It's also the unit of failure, and is fully autonomous. Event streaming plays a vital role in the microservices architecture and can be used as the communication fabric between the services. It can also be used as the fabric for capabilities like integration, replication, consensus, and persistence.
Regarding data persistence, CRUD services are fine for totally isolated data, but achieving consistency is very challenging across CRUD services. You will have to rely on eventual consistency from the beginning of application design and use strong consisency only where needed instead of the other way around. He also discussed the importanace of modeling our systems to address the uncertainty. The management of uncertainty must be implemented in the business logic. Events can help us manage failure instead of trying to avoid it. Use CRUD services together with event streams to get an internally consistent material view.
Event logging and event sourcing are also critical in realizing scalable microservices architectures. Just like a transaction log is used in relational databases, the event log is the bedrock and helps with scalability, reliability, and consistency. Event sourcing also helps with eventual consistency between the microservices, and can help with recovering from failure by "rehydrating" events from the event log. It also allows others to subscribe to state changes. You can also use the CQRS design pattern to untangle the read and write models. Reads in the system may have completely different characteristics compared to the writes.
Bonér concluded the presentation saying that events-first design helps create a resilient and scalable architecture and the design of autonomous microservices. Event logging allows you to avoid CRUD and ORM, and take control of your system's history, and balance between strong and eventual consistency models.
Akka framework is a good solution for implementing these patterns. For more information on events-first microservices, you can check out his mini book titled Reactive Microsystems.