Command Query Responsibility Segregation (CQRS) with Domain Driven Design is getting more and more popular recently. Its implementation in PHP, which will be the topic of the article, generates some new possibilities, making a process more efficient. For example, it gives you the opportunity to restore the whole system easily. Also, it enables asymmetric scalability, guarantees no data loss and many more. I’ve decided to divide the text into four parts to make sure the subject is presented in an exhaustive way.
Before I step to the CQRS and Event Sourcing implementation in PHP – I’ll try to briefly explain what is the general concept behind CQRS. In 1986, Bertrand Meyer came up with an idea of Command Query Separation (CQS). According to the concept – each method in the object must belong to only one category out of the following two:
– command – a method which changes an object’s state,
– query – a method which returns the data.
It means that all the queries should return the same result as long as you didn’t change the object’s state with a command.
As you can see below, in the first example – the rule is broken by the method `increase()` which shouldn’t return the value. In the second one, there is a presentation of proper implementation.
I’m mentioning that because CQRS is derived directly from the same concept. However, it’s not related to the object/component but rather to the whole system or bounded context, which is logically separated part of the system, responsible for a realisation of certain tasks. Let’s take an example of a simple webstore. We can separate the following contexts: a purchase, a delivery or a complaint.
CQRS is a style of application’s architecture which separates the “read” operations and the “write” operations on the bounded context level. It means that you create 2 data models – one for writing and the other for reading. It’s presented on the scheme below.
As you can see, implementation of a logic responsible for writing is independent of an implementation of a logic responsible for reading. In practice, it enables a better fit of the read/write models to the requirements. A read model may be flattened and may serve aggregated data. At the same time – it doesn’t have to calculate these in real time. In the case of a common model of read/write, this kind of data is redundant and it only introduces unnecessary “chaos”, complicating a writing model.
What is Event Sourcing and Event Store?
Let’s imagine a basic example of making an order in a webstore with digital cameras.
- You add a camera to the cart.
- You add a memory card.
- You increase the number of memory cards up to 2.
- You make an order based on the cart content, choose the delivery and payment methods.
- You make a payment.
The whole process is a series of subsequent events. In a traditional approach, you apply the changes (which come from the above events) to the cart’s objects and then to the order’s objects. Next, you write its state in the database.
What if you write subsequent events as they happen instead of writing the final effect? In this case, reconstitution of the objects will be about creating an empty object and applying these events. This object should have exactly the same state as the one written in a database in a traditional approach.
The described method is Event Sourcing. The events connected to the object are the source of the data – not its final state.
Event Bus is an important element in communication between write and read models. Event Bus is a mechanism which enables communication between different components, which not necessarily know about each other. One of the elements is publishing events (so-called publisher) and it doesn’t know what components (known as subscribers) are using it and how many components like this are there. On the other side – the components don’t know what is publishing the events.
In CQRS, all the changes are done in a write model. It generates the events which inform about the changes. The events are published through Event Bus, then these are consumed by a read model. Thanks to that, a read model is informed about all the changes and can react. In other words – it can change the status of served objects.
Event Store is a database optimized for events recording. In the Event Store, you can only write the events and the data connected to them. Domain objects are not written in the database, they only exist in a memory and are reproduced on the basis of events which happened.
Below, there’s an example of an event object which informs about a user creation.
As you can see, the object contains only primitive types. It’s done on purpose. Thanks to that, you can easily serialize objects to write them in the database and to store them in the message queueing systems. There, they can wait to be processed.
Pros and cons of Event Sourcing
Event Sourcing, like every other approach, has its pros and cons.
Pros of Event Sourcing:
– no data loss; everything that happened since the system has been created is written in Event Store,
– asymmetric scalability; you can scale a part responsible for reading independently of the one dedicated for writing;
– you can restore the whole system, basing on the events,
– you have access to the whole history of the changes in the domain objects (natural audit),
– you can divide the work in the team in a better way; writing model is normally way more complex and it requires better knowledge.
On the other hand, it has some cons:
– eventual consistency; not all the changes are available immediately, sometimes you need to wait for the events processing,
– the existence of two models (read/write),
– higher complexity of the app,
– little support from frameworks/libraries.
What is Broadway and what components it gives us?
There are 2 libraries which give full support for CQRS/ES in PHP: Broadway and Prooph. Taking into consideration the fact that some components developed by Prooph will soon be cancelled (you can read more about it here) – there will be Broadway only.
But what is Broadway?
The authors come up with the below definition on the project’s official website:
Broadway is a project providing infrastructure and testing helpers for creating CQRS and event sourced applications.
As you can see, Broadway is the library which provides the infrastructure. It enables the creation of the PHP application which is based on Event Sourcing and CQRS. In practice, it means that we get full support for this architecture. Broadway provides the following components:
– Auditing – logging all the commands,
– CommandHandling – support for the Command Bus,
– Domain – support for domain objects; it includes the abstraction for aggregate roots and domain message/events,
– EventDispatcher – component Event Dispatcher,
– EventHandling – event’s support,
– EventSourcing – support for event sourced aggregate roots, event source repository implementation,
– EventStore (Doctrine DBAL, MongoDB) – support for databases for writing events,
– Processor – it supports the application’s processing,
– ReadModel (Elasticsearch, MongoDB) – support for read model with the database(Elasticsearch or MongoDB),
– Repository – abstraction of the storage of aggregates,a
– sensitive data handling – it helps handling the events which include sensitive data (and it doesn’t save it in Event Store),
– Serializer – it supports serialization and deserialization of the data.
In the first part of the article about CQRS and Event Sourcing implementation in PHP, I’ve focused on the general idea of CQRS, Event Sourcing and Event Store. Also, I’ve presented the pros and cons.
The second part of the article will be about the implementation of the write model with Broadway library.