How to structure the query-side of a CQRS application?

Viewed 259

I am working on two different services:

  1. The first one handles all of the write operations through a REST API, it contains all of the required business logic to maintain data in a consistent state, and it persists entities on a database. It also publishes events to a message broker when an entity is changed (creation, update, deletion, etc). It's structured in a DDD fashion.
  2. The second one only handles reads, also with a REST API. It subscribes to the same message broker in order to process the events published by the first service, then it saves the received data to an in memory database for fast reads.

Nothing fancy, just CQRS with eventual consistency.

For the first service, I had a clear mind on how to structure the application:

  • I have the domain package with subpackages for each different aggregate. Each aggregate has its own domain objects, and its own repository interface.
  • I have the application package with different application services, and they basically just orchestrate the domain objects and call repositories to persist/update data, and the event publisher to publish domain events. The event publisher interface is also in this package.
  • I have the infrastructure package, which includes a persistence package, where the repository implementations reside, and a messaging package, where the event publisher implementation resides.
  • Finally, the interfaces package is where I keep the controllers/handlers for the REST API.

For the second service, I'm very unsure on how to structure it. My doubts are the following:

Should I use the repository pattern? To be fair it seems redundant and not very useful in this scenario. There are no domain objects nor rules here, cause the data to be saved/updated is already validated by the first service.

If I avoid using the repository pattern, I suppose I'd have to inject the database client in my application service, and access the data directly. Is this a good practice? If yes, where would the returned objects fit? Would they also be part of the application layer?

Would it make sense to skip the application service entirely and inject the database client straight up in the controller/handler? What if the queries are a bit complicated? This would pollute the controllers with a lot of db logic, making it harder to switch implementations (there would be no interface in this case).

What do you think?

1 Answers

The Query side will only contain the methods for getting data, so it can/should be really simple.

You are right, an abstraction on top of your persistence like a repository pattern can feel redundant. You can actually call the database in your controller. Even when it comes to testing, on the query side you only need basically integration tests that test the actual database. Having unit tests won't test much.

On the other hand, it can make sense to wrap the database calling logic in a query service similar to a repository. You would inject only that query service interface in your controller, which should use your ubiquitous language! You would have all the db logic in this query service and keep the db complexity there, while keeping the controller really simple. You can avoid complex queries by having multiple read models based on your events depending on your needs.

Related