CQRS read models in hexagonal architecture

1,469 views
Skip to first unread message

Andrew Easter

unread,
Aug 18, 2016, 4:28:23 PM8/18/16
to DDD/CQRS
Hey all.

Just thought I'd ask for people to share some insight as to how they normally fit read models into the typical infrastructure/application/domain structure associated with hexagonal architecture. It's pretty clear to me how the write-side fits into the classic layers, but I'm not sure how others conceptually treat the read-side. Do you treat read models (views) as part of the domain model? If so, is it just a case of defining something akin to read only repositories (and some kind of DTOs) in the domain layer, with the actual repository implementations in the infrastructure layer? Where does the logic exist that determines how events feed into the read model? Is that domain or application logic?

Have I already asked too many questions? ;-)

Would love to hear others' experiences.

Cheers,
Andrew

urbanhusky

unread,
Aug 19, 2016, 1:44:14 AM8/19/16
to DDD/CQRS
I've naively placed read models (and projections) in the application layer. The read models don't have any invariants to guard and they pretty much map directly to corresponding views (presentation).
To me, they are just containers for data in a specific format - so there is no harm in returning them directly.

Also, I avoid repositories on the read side because I do not need or want any abstraction from the underlying persistence. Especially not a generic repository that covers RDBMS, document databases or even graph databases - that would not really make any sense. We'd lose all the great performance and technology-specific features. We expose the read models via a simple web API - the API itself then accesses the databases directly (in our case, .net - so entity framework context, raven db session etc.).

Andrew Easter

unread,
Aug 19, 2016, 3:47:02 PM8/19/16
to DDD/CQRS
Interesting points. I get what you're saying about avoiding abstracting the underlying datastore(s) on the read-side - given one motivation for CQRS is to optimise read models, makes sense not to throw in a whole bunch of abstractions that reduce one's ability to achieve such optimisations. 

So, I guess your view is that read models are not part of the domain, and are essentially application concerns?

Alexandre Potvin Latreille

unread,
Aug 25, 2016, 9:18:55 PM8/25/16
to DDD/CQRS
I'm also interested in this question. I'm tempted to define an application.query namespace which would hold the query service interfaces as well as DTOs and implement those services in the infrastructure.query layer to avoid having SQL directly in the application layer. Does that make sense? Perhaps the read model should be an entirely different BC? The only problem I'd see with that is with synchronous projections...

Kirill Chilingarashvili

unread,
Aug 26, 2016, 6:04:54 AM8/26/16
to DDD/CQRS
I tried to breakdown domain-application-infrastructure standard schema, but I identified a lot of other building blocks in CQRS application I am working on.

I find easier to explain my app as set of four types of modules

- kernel
- context specific 
- infrastructure
- host

In kernel there are the following features (building blocks)
- event
- domain (depends on event)
- query
- projection (depends on event and query)
- api
- scheduler (depends on event)
- saga (depends on event, domain and scheduler)

kernel is not bound to any infrastructure
every feature is implemented as module, and module instance is responsible for doing feature specific task relying on abstractions
(for example domain feature provides Engine, which can execute commands)

context specific has different number of blocks from context to context, but they can be
- context domain (defines aggregates, and commands/events)
- context query (defines query schema)
- context projection (defines what events from context domain to project to what schema from query)
- context api (exposes UI-specific api, relying on context domain and context query)
- context saga (implements eventual consistent business processes based on context domain, may reference context query as well)

infrastructure layer implements abstractions used by features in kernel, and may be:
- sql server event store
- katana self hosted web api
- sql server query
- sql server scheduler
- sql server event provider

there may be more than one infrastructure for provider

and last big group of blocks is hosts, hosts are separately hostable process bootstrappers, they may bootstrap a  lot of endpoints in a single process or in many separate processes. The typical hosts can be:
- api host (uses katana web api,  sql server event store and sql server query for context api which relies on context domain and context query)
- projection worker host (uses sql server event provider, sql server query, context domain events, context query, context projection)
- saga worker host (uses sql server event store, event provider, scheduler and query, with context saga etc)

I think query is not for UI api only, it may also be used by sagas (business processes) - for example send email to all admins - where all admins are in read model
Also I think it makes sense to separate projection from query, as you may change strategy of populating query later with different projection methods
Reply all
Reply to author
Forward
0 new messages