I still remember good old days of repositories. But repositories used to grow ugly with time. Then CQRS got mainstream. They were nice, they were a breath of fresh air. But recently I've been asking myself again and again why don't I keep the logic right in a Controller's Action method (especially in Web Api where action is some kind of command/query handler in itself).

Previously I had a clear answer for that: I do it for testing as it's hard to test Controller with all those unmockable singletons and overall ugly ASP.NET infrastructure. But times have changed and ASP.NET infrastructure classes are much more unit tests friendly nowadays (especially in ASP.NET Core).

Here's a typical WebApi call: command is added and SignalR clients are notified about it:

public void AddClient(string clientName)
{
    using (var dataContext = new DataContext())
    {
        var client = new Client() { Name = clientName };

        dataContext.Clients.Add(client);

        dataContext.SaveChanges();

        GlobalHost.ConnectionManager.GetHubContext<ClientsHub>().ClientWasAdded(client);
    }
}

I can easily unit test/mock it. More over, thanks to OWIN I can setup local WebApi and SignalR servers and make an integration test (and pretty fast by the way).

Recently I felt less and less motivation to create cumbersome Commands/Queries handlers and I tend to keep code in Web Api actions. I make an exception only if logic is repeated or it's really complicated and I want to isolate it. But I'm not sure if I'm doing the right thing here.

What is the most reasonable approach for managing logic in a typical modern ASP.NET application? When is it reasonable to move your code to Commands and Queries handlers? Are there any better patterns?

Update. I found this article about DDD-lite approach. So it seems like my approach of moving complicated parts of code to commands/queries handlers could be called CQRS-lite.

有帮助吗?

解决方案

Is CQRS a relatively complicated and costly pattern ? Yes.

Is it over-engineering ? Absolutely not.

In the original article where Martin Fowler talks about CQRS you can see a lot of warnings about not using CQRS where it's not applicable:

Like any pattern, CQRS is useful in some places, but not in others.

CQRS is a significant mental leap for all concerned, so shouldn't be tackled unless the benefit is worth the jump.

While I have come across successful uses of CQRS, so far the majority of cases I've run into have not been so good...

Despite these benefits, you should be very cautious about using CQRS.

...adding CQRS to such a system can add significant complexity.

My emphasis above.

If your application is using CQRS for everything, than it's not CQRS that's over-engineered, it's your application. This is an excellent pattern to solve some specific problems, especially high performance/high volume applications where write concurrency may be a major concern.

And it may not be the entire application, but only a small part of it.

A live example from my work, we employ CQRS in the Order Entry system, where we cannot lose any orders, and we do have spikes where thousands of orders come at the same time from different sources, in some specific hours. CQRS helped us to keep the system alive and responsive, while allowing us to scale well the backend systems to process these orders faster when needed (more backend servers) and slower/cheaper when not needed.

CQRS is perfect for the problem where you have several actors collaborating in the same set of data or writing to the same resource.

Other than that, spreading a pattern made to solve a single problem to all your problems will just create more problems to you.


Some other useful links:

http://udidahan.com/2011/04/22/when-to-avoid-cqrs/

http://codebetter.com/gregyoung/2012/09/09/cqrs-is-not-an-architecture-2/

其他提示

CQRS is not a one-for-one replacement for Repositories, exactly because it's a complex, costly pattern which is only useful in some cases.

Here's what Udi Dahan has to say in merit:

Most people using CQRS (and Event Sourcing too) shouldn’t have done so.

[...]

I’m sorry to say that most sample application you’ll see online that show CQRS are architecturally wrong. I’d also be extremely wary of frameworks that guide you towards an entity-style aggregate root CQRS model.

(source)

Martin Fowler:

[...] you should be very cautious about using CQRS. Many information systems fit well with the notion of an information base that is updated in the same way that it's read, adding CQRS to such a system can add significant complexity.

(source)

Finally, Greg Young:

CQRS can be called an architectural pattern.

[...]

This is very important to understand most architectural patterns are not good to apply everywhere. If you see architectural patterns in an architectural guideline you probably have a problem

[...]

The largest failure I see from people using event sourcing is that they try to use it everywhere.

(source)

许可以下: CC-BY-SA归因
scroll top