Разве CQRS не является переобработкой?

15

Я до сих пор помню старые добрые времена хранилищ. Но хранилища со временем становились безобразными. Тогда CQRS получил господствующую тенденцию. Они были хороши, они были глотком свежего воздуха. Но в последнее время я снова и снова спрашиваю себя, почему я не придерживаюсь логики в методе Controller's Action (особенно в Web Api, где action сам по себе является своего рода обработчиком команд / запросов).

Ранее у меня был четкий ответ на этот вопрос: я делаю это для тестирования, так как сложно протестировать Controller со всеми этими немодными синглетонами и общей уродливой инфраструктурой ASP.NET. Но времена изменились, и классы инфраструктуры ASP.NET стали гораздо более удобными для модульных тестов (особенно в ASP.NET Core).

Вот типичный вызов WebApi: команда добавлена, и клиенты SignalR уведомляются об этом:

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);
    }
}

Я могу легко провести юнит-тест / издеваться над ним. Более того, благодаря OWIN я могу настроить локальные серверы WebApi и SignalR и провести интеграционный тест (и, между прочим, довольно быстро).

В последнее время я чувствовал все меньше и меньше мотивации для создания громоздких обработчиков команд / запросов, и я склонен держать код в действиях Web Api. Я делаю исключение, только если логика повторяется или она действительно сложна, и я хочу ее изолировать. Но я не уверен, правильно ли я здесь поступаю.

Каков наиболее разумный подход к управлению логикой в ​​типичном современном приложении ASP.NET? Когда целесообразно переместить ваш код в обработчики команд и запросов? Есть ли лучшие образцы?

Обновить. Я нашел эту статью о подходе DDD-Lite. Похоже, мой подход к переносу сложных частей кода в обработчики команд / запросов можно было бы назвать CQRS-lite.

SiberianGuy
источник
1
Я не вижу, как CQRS делает вещи более тестируемыми / помогает с одиночными / контроллерами / и т.д. Они в основном не связаны. Кроме того, вы все еще создаете команду в вашем (counter?) Примере, что странно.
guillaume31
Если вы храните свой код в коде инфраструктуры (например, получаете IP-адрес клиента), его сложно протестировать. Если вы изолируете логику в запросе / команде, это будет намного проще. Пример кода был немного запутанным, поэтому я обновил его.
SiberianGuy
1
Запросы и команды не имеют логики. Они тупые DTO. Тогда у вас есть ваши обработчики команд / запросов , но они точно такие же, как службы приложений, интеракторы, бизнес-службы, вы называете это ... в контексте, отличном от CQRS. Размещение аппликативной логики / логики использования в отдельном объекте, отличном от контроллера, не является специфической особенностью CQRS.
guillaume31
Кроме того, вопрос зависимости Синглтона от введенной полностью ортогональн к CQRS. Вы могли бы иметь Контроллер, вызывающий синглтон CommandHandler, который вызывает синглтон Репозиторий ...
guillaume31
1
@ guillaume31, CQRS имеет тенденцию быть более громоздким, чем вызовы службы репозитория / приложения. Обычно им требуется 2-3 класса (то есть запрос, обработчик запросов, результат запроса), инфраструктура и т. Д.
SiberianGuy

Ответы:

17

Является ли CQRS относительно сложной и дорогостоящей моделью? Да.

Это чрезмерная инженерия? Точно нет.

В оригинальной статье, где Мартин Фаулер говорит о CQRS, вы можете увидеть множество предупреждений о том, что не следует использовать CQRS там, где это не применимо:

Как и любой шаблон, CQRS полезен в некоторых местах, но не в других.

CQRS является значительным умственным скачком для всех заинтересованных сторон, поэтому его не следует решать, если вы не выиграете .

Хотя я сталкивался с успешным использованием CQRS, до сих пор большинство случаев, с которыми я сталкивался, были не такими хорошими ...

Несмотря на эти преимущества, вы должны быть очень осторожны при использовании CQRS .

... добавление CQRS в такую ​​систему может значительно усложнить задачу .

Мой акцент выше.

Если ваше приложение использует CQRS для всего, то это не CQRS, а слишком ваше приложение. Это отличный шаблон для решения некоторых специфических проблем, особенно в приложениях с высокой производительностью и большим объемом, где параллелизм записи может быть серьезной проблемой.

И это может быть не целое приложение, а лишь небольшая его часть.

Живой пример из моей работы: мы используем CQRS в системе ввода заказов, где мы не можем потерять какие-либо заказы, и у нас есть всплески, когда тысячи заказов поступают одновременно из разных источников в определенные часы. CQRS помог нам поддерживать работоспособность системы и ее адаптивность, в то же время позволяя хорошо масштабировать бэкэнд-системы, чтобы обрабатывать эти заказы быстрее, когда это необходимо (больше бэкэнд-серверов), и медленнее / дешевле, когда не нужно.

CQRS идеально подходит для задачи, когда у вас есть несколько действующих лиц, сотрудничающих в одном наборе данных или пишущих в один и тот же ресурс.

Кроме того, распространение шаблона, созданного для решения одной проблемы на все ваши проблемы, просто создаст вам больше проблем.


Некоторые другие полезные ссылки:

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

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

Мачадо
источник
3
Согласитесь на все, кроме «относительно сложной и дорогостоящей модели». CQRS просто отделяет чтение от записи. Вы можете сделать это с помощью клейкой ленты, нулевого промежуточного программного обеспечения / сложного инструментария и сохраняя ту же базу данных, что и раньше, несмотря ни на что.
guillaume31
@ guillaume31, это справедливо. Я думаю, что это вполне соответствует идее из исходного вопроса: «в Web Api, где действие - это некая команда / запрос сама по себе». Но видели ли вы какие-нибудь рабочие примеры CQRS (предпочтительно github), в которых не используются отдельные классы для команд и запросов? Вот что я нахожу, когда пытаюсь понять, как другие люди внедряют CQRS в .NET.
SiberianGuy
Да, но это не перегрузка. Это основная предпосылка шаблона - отделение запросов от записей, модели чтения от модели домена.
guillaume31
CQRS подход может быть более убить во многих контекстах, но это совсем другая история. Это не излишество из-за всех мелких технических деталей, которые вы ошибочно приписываете CQRS в своем Q, это излишне, потому что вам не всегда нужно то, что приносит вам CQRS.
guillaume31
Я думаю, что точка зрения Фаулера действительна только до определенного момента. SQL Views - это один из типов CQRS, который существует у нас целую вечность, и никто не говорит, что он очень сложный. Поскольку существует много разновидностей CQRS, то есть прогнозов источников событий, которые могут рассматриваться как сложные в одних областях, а в других могут быть тривиальными.
Алексей Зимарев
3

CQRS не является заменой репозиториев «один на один», потому что это сложный, дорогостоящий шаблон, который полезен только в некоторых случаях.

Вот что Уди Дахан должен сказать по существу:

Большинство людей, использующих CQRS (и Event Sourcing тоже), не должны были этого делать.

[...]

Сожалею, что большинство примеров приложений, которые вы видите в Интернете и показывающих, что CQRS архитектурно неверны. Я также был бы крайне осторожен с фреймворками, которые направляют вас к модели агрегированного корневого CQRS в стиле объекта.

( источник )

Мартин Фаулер:

[...] вы должны быть очень осторожны при использовании CQRS . Многие информационные системы хорошо согласуются с понятием информационной базы, которая обновляется так же, как она читается, добавление CQRS в такую ​​систему может значительно усложнить задачу.

( источник )

Наконец, Грег Янг:

CQRS можно назвать архитектурным паттерном.

[...]

Это очень важно понимать, что большинство архитектурных моделей не очень хорошо применять везде. Если вы видите архитектурные образцы в архитектурном руководстве, у вас, вероятно, есть проблема

[...]

Самая большая ошибка, которую я вижу у людей, использующих источник событий, заключается в том, что они пытаются использовать его везде.

( источник )

Sklivvz
источник