1

I was reading the infrastructure persistence layer design documentation, and this quote has me confused:

This'll probably be my biggest feedback. I'm really not a fan of repositories, mainly because they hide the important details of the underlying persistence mechanism. It's why I go for MediatR for commands, too. I can use the full power of the persistence layer, and push all that domain behavior into my aggregate roots. I don't usually want to mock my repositories – I still need to have that integration test with the real thing. Going CQRS meant that we didn't really have a need for repositories any more.

I don't understand how can using CQRS mean we don't need repositories anymore. Command handlers should be in the application service layer, correct? That layer should not be aware of any persistence mechanism so it's not like we can implement our data access methods there.

Any insight?

10
  • 1
    DDD and CQRS are different concepts. They are complimentary, for sure, but different. An equally valid question could be "In DDD, why is CQRS optional?" Domain-Driven Design is more of a philosophy than a design pattern. CQRS is a design pattern. Aug 10, 2023 at 17:12
  • I'm well aware that they are different, what made you think I did not? More importantly, how is that relevant to my question? Aug 10, 2023 at 17:15
  • I'm not understanding how you think repositories are required in DDD. The quote in your question talks about CQRS and repositories, not DDD and repositories. It made me think there was a mixup in these two buzzwords. Aug 10, 2023 at 17:20
  • 4
    None of the DDD tactical patterns (including repositories) are mandatory, that's part of the point of DDD. Eric Evans suggested a set of patterns that you can use to effect your modeling in code, but you can in principle come up with a completely different set of patterns, and it would still be DDD. If you're following a canned/prescribed "DDD" architecture without doing the analysis/modeling part of the job, you're not doing DDD. Specifically, you're not doing the "Domain Driven" part of it. Aug 10, 2023 at 17:46
  • 1
    I couldn't find the source of the quote, but this seems to be where the idea originated. It's a slightly different design; his query objects are not substantially different from single-method, application-specific repositories; the key difference is that the data source is injected externally, so the object only encapsulates the query itself. Aug 10, 2023 at 18:11

2 Answers 2

1

The question (and title) is steeped in a general conflation of different concepts such as DDD, CQRS and the repository pattern, and implied statements that they are mutually exclusive or that they are different solutions to the same problem.

None of that is the case. These three concepts all act on a different scope, and can be implemented (or not) without that therefore requiring/excluding the implementation of the others.

Command handlers should be in the application service layer, correct?

There's nothing in the definition of CQRS that dictates that this is an application layer implementation. CQRS dictates that you split your logic across individual handlers (as opposed to e.g. bundling them in a single service interface).

However, one can implement this kind of separation in any layer they want to. This could be implemented on the Application layer (and to be fair it commonly is), but it could just as well be implemented on the Persistence layer.

There's no conclusive answer here, other than "no, it's not inherently about the Application layer".

I don't understand how can using CQRS mean we don't need repositories anymore.

Generally speaking (observe that I'm going to address fringe definitions in a moment), repositories are thought of as the same kind of service interface that bundles all of the interactions (commands, queries) related to a particular data store (commonly scopes to a particular database table), just like I described before. Using this interpretation, one could inherently imply that repositories are at odds with CQRS in the sense that repositories bundle the operations whereas CQRS inherently prescribes their separation.

However, there is wiggle room in all of these definition and interpretations.

For example, one could separate their classic repository into a read repository and a write repository. The queries are then not individually separate (neither are the commands), but the queries are separated from the commands and this sufficiently satisfies the definition of CQRS.

Another thing to point out might be that the CQRS separation might only be enforced on the interface level, i.e. the application talks to the persistence layer using individually decouples query/command objects/interfaces. But in the actual implementation of the persistence layer, there might still be a single repository that implements multiple of these interfaces/handlers.

This can make sense in cases where you want to have some reusability (I'm thinking of e.g. a reusable repository mock for testing purposes), or if you want your overall codebase to already be CQRS-compatible even though you haven't actually separated your read and write stores themselves just yet. Not a common scenario but one I have concretely encountered.

You'll notice that I haven't yet brought up DDD, and there's no reason to do so. DDD is completely unrelated to this alleged conflict between CQRS and repositories. Sure, in a DDD context your specific syntax is going to look a bit different, but its inclusion (or lack thereof) doesn't impact the general considerations that this answer touched on.

The main point here is that depending on your specific definition of CQRS and repositories, they could be interpreted as being polar opposites or not. So you could be right, as could the person who you are quoting and seemingly disagreeing with.

6
  • -1. Unless the Repository pattern has morphed beyond recognition since last time I looked, I disagree with that description. Repository is both an older OO pattern and a DDD pattern, but OP and the Microsoft article refer to the latter. Saying that it bundles all of the interactions (commands, queries) is a very far fetch. Firstly Repositories only deal with Aggregates. Then there are two implem traditions, one that acts as a mere collection and another that is a bit closer to storage but certainly doesn't map to all of a system's Commands (see "Implementing DDD", V. Vernon, p.365). Aug 11, 2023 at 8:43
  • @guillaume31 You're going well beyond the current question's context here. The comparison was between a repository and CQRS, where CQRS dictates a separation that repositories do not. Splitting hairs over the exact type of bundling is beside the point I was making that a repository bundles things more so than CQRS prescribes. As the second to last paragraph points out DDD does not factor into this particular consideration. Yes, DDD makes some difference here for the overall architecture and syntax, but not in a way that it meaningfully changes the considerations listed in this answer.
    – Flater
    Aug 11, 2023 at 11:41
  • First sentence of section 1 in the referenced Microsoft article: The Repository pattern is a Domain-Driven Design pattern. This makes me think OP had DDD in mind and in that context, the type of repository matters. The text excerpt quoted by @MyUsername112358 also mentions Aggregate roots. It makes a huge difference whether your Repository only deals with Aggregate roots or not. Aug 11, 2023 at 11:50
  • @guillaume31: Unless you can show me the that this kind of DDD-specific repository pattern explicitly prescribes using only a single query or command per type in the same way that CQRS does, the distinction you're pointing at simply doesn't matter here. I'm not saying the distinction doesn't exist when discussing the overall codebase, I'm saying it doesn't make a difference with regards to the actual focus of this particular answer.
    – Flater
    Aug 11, 2023 at 11:53
  • I will not show it because Jimmy Bogard, author of the quote in OP, shows it at length in the blog posts referenced in my answer. For him Aggregates are the crux of the matter, a huge part of why Repositories conflict with CQRS in his opinion. Aug 11, 2023 at 11:56
1
  1. The quote is precisely about Bogard breaking the persistence-unawareness rule, willing to embrace some amount of coupling with his persistence technology/framework for the sake of simplicity and flexibility. ORMs usually already provide data objects that look like repositories anyway. His application services (or even controllers) will call these objects directly, without a data access abstraction layer.

So I’m over Repositories, and definitely over abstracting your data layer, but where does that leave us? I don’t think creating an abstraction over your ORM provides much value

https://lostechies.com/jimmybogard/2012/10/08/favor-query-objects-over-repositories/

i dont use a repository with EF because it already implements the pattern (as well as the identity map pattern)

but i do with MongoDB because its client does not implement either

https://twitter.com/jbogard/status/1188810487364030464?lang=en

  1. As for going CQRS meant that we didn't really have a need for repositories any more, it seems that his gripes are more with Aggregates than Repositories per se.

One part of it is that Aggregates are no longer a valid unit of data on the read side in a CQRS world where you want ad-hoc queries. Something that I personally always thought went without saying, and didn't necessarily mean you couldn't have Repositories on the write side and something else on the read side. But I guess in the late 2000s things were a lot more blurry and it was not a granted.

On virtually every screen our application, we show the exact same entity. That’s around 150 screens or so, where what you see begins with one Person, and filters down from there. This made things quite interesting from the query optimization standpoint. We had two choices – go through the root Person entity to all of its children, in one slice. Or, go from the children, and get back to the parent. But sometimes we show bits and pieces of various slices of our Person object, things that did not fit well with just one Repository call.

On the write side, his problem is with implementing complex persistence logic in repositories that could be easily replaced with ORM cascades. Something that I cannot speak to since I never encountered the need to model commands spanning multiple aggregates in a lot of slightly different ways for each screen.

Thus it started to become confusing how we should handle cascades and save logic. Since boundaries varied screen-to-screen, it became obvious that any custom save logic in a Repository could be handled perfectly well in the ORM layer, with cascades. Eventually, our model became extremely connected, with appropriate cascading and modification operations available only when specifically needed.

https://lostechies.com/jimmybogard/2009/09/11/wither-the-repository/ (hard to find because "CQS" is used in place of "CQRS" there)

4
  • You've misrepresented their point about repositories. It's not that they don't use a repository pattern, it's that they consider EF to already be a repository pattern and they don't bother with wrapping that in a second homebrew repository pattern. There's a significant difference between "I don't use this" and "I don't need another because I already have one". Using EF does not break the persistence unawareness rule, as the EF context and dbset do not reveal what the underlying persistence technology is. One can keep using EF (unchanged!) while swapping out the underlying data provider.
    – Flater
    Aug 11, 2023 at 11:50
  • Using EF does not break the persistence unawareness rule : though I differ, this should have been your answer! Instead of side tracking into false assumptions about DDD. Aug 11, 2023 at 12:07
  • Also see my opinion about EF vs persistence ignorance: softwareengineering.stackexchange.com/a/384966/15150 Aug 11, 2023 at 12:12
  • 1
    @Flater I guess motivation for "persistence unawareness" is less about persistence-independence, and more about being implementation-independent, and then you get into what you consider to be "implementation details" - i.e. do you also want isolation from data access libraries or not. It depends on the needs of the project. Once I talked to someone who argued that such isolation is a theoretical thing, 'cause "who ever ends up changing their DB" - and then proceeded to tell me how they were spending nontrivial effort migrating a legacy project from Linq-to-SQL to EF. Aug 12, 2023 at 11:17

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.