Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

CQRS or App Service?

So I like the concepts of CQRS in our application, mainly because we already support event sourcing (conceptually, not following any prescriptions that you see out there). However, it really seems like CQRS is geared toward Big Data, Eventual consistency, that kind of thing. We are always going to be a Relational DB app, so I am not sure if it fits.

I also have concerns because I think I need to do some special things in my app layer. When doing a read, I need to enforce security and filter data, things that are traditionally implemented in the application layer.

My first question is, does my app fit (a traditional MVC / Relational DB app)? Or does it make more sense to have a traditional app layer and use a DTO Mapper?

My second question is, does it make sense to issue commands to your domain model out of a traditional application layer? I like the idea of commands / command handlers and eventing.

Let me clarify my question. I have concerns around data filtering that are tied to authorization. When a user requests data, there has to be a filter that restricts access to certain data elements by removing them all together (So they are not returned to the caller), hiding the values, or applying masks to the data. In a contrived example, for a Social Security Number, the user making the request may only be able to see the last 4 numbers, so the result would appear like ###-##-1234.

My assertion is that this responsibility goes in the Application layer. I consider this an aspect, where all responses to queries or commands have to go through this filter mechanism. Here is where my CQRS naivity shines through, perhaps it is that commands never return data, just pointers to data that are looked up through the read model?

Thanks!

like image 998
noplay Avatar asked Sep 27 '12 13:09

noplay


1 Answers

First and foremost: CQRS and Relational Databases don't exclude each other. In advanced scenarios it may make sense to replace the SQL-based DB with other means of storage, but CQRS as a concept doesn't care about the persistence mechanism.

In the case of multiple views that depend on roles and/or users, the Thin Read Layer should probably provide multiple result sets:

  1. One containing the full SSN for users that are authorized to access that information.
  2. A different one for users that are not authorized to see that information
  3. ...

These can be stored in a separate data store, but they can also be provided through SQL views if you work with a single SQL-based database.

In CQRS the Application Service still exists in the form of Command Handlers. These can be nested, i.e. handling authorization first, then posting the command to a contained command handler.

public class AuthorizationHandler {

    public CrmAuthorizationService(CrmCommandHandler handler) {
        _next = handler;
    }

    public void Handle(SomeCommand c) {
        if (authorized) _next.Handle(c);
    }
}

// Usage:
var handler = new CrmAuthorizationService(new CrmCommandHandler());
bus.Register<SomeCommand>(handler.Handle);

This way you can nest multiple handlers, e.g. as a REST envelope, for logging, transactions, etc.

To answer your questions:

First: Is CQRS a good fit for your app? No-one can tell without really digging into the specific requirements. Just because you use MVC and a relational DB doesn't mean anything when it comes to the pros and cons of CQRS.

Second: Yes, in some cases it can make sense to let your application layer interact with the client in a classical way and handle things like authentication, authorization, etc., and then issue commands internally. This can be useful when putting an MVC-based UI or a REST API on top of your application.

Update in response to comment:

In an ideal, puristic CQRS scenario Sally would have her own denormalized data for every view, e.g. a couple of documents in a NoSQL DB called CustomerListForSally, CustomerDetailsForSally, etc. These are populated with what she's allowed to see.

Once she gets promoted - which would be an important domain event - all her denormalized data would automatically be overwritten, and extended to contain what she's allowed to see now.

Of course we must stay reasonable and pragmatic, but this ideal should be the general direction that we're heading for.

In reality you probably have some kind of user/role or user/group based system. To be able to view sensitive information, you'd have to be member of a particular role or group. Each of these could have their defined set of views and commands. This doesn't need t be denoalized data It can be as simpe as a cope of SQL-Views:

  • CustomerDetailsForSupportStaff
  • CustomerDetailsForSupportExecutive with unmasked SSN
  • CustomerListForSupportStaff
  • CustomerListForSupportExecutive with customer revenue totals
  • etc.
like image 94
Dennis Traub Avatar answered Oct 24 '22 23:10

Dennis Traub