Чи не перенапруження CQRS?


15

Я все ще пам’ятаю старі добрі часи сховищ. Але сховища звикли рости з часом некрасиво. Тоді CQRS отримав мейнстрім. Їм було приємно, вони затамували свіже повітря. Але останнім часом я знову і знову запитую себе, чому я не дотримуюся логіки правильно в методі дій Controller's Action (особливо в Web Api, де дія є якоюсь самою обробкою команд / запитів).

Раніше у мене була чітка відповідь на це: я роблю це для тестування, оскільки важко перевірити контролер з усіма цими нерозбірними сингтонами та загальною потворною інфраструктурою 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.


1
Я не бачу, як CQRS робить речі більш перевіреними / чи допомагає одиночним кнопкам / контролерам / тощо. Вони значною мірою не пов'язані між собою. Крім того, ви все ще створюєте команду у своєму (лічильнику?) Прикладі, що дивно.
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 - це один із типів CQRS, і він є у нас віками, і ніхто не каже, що вони дуже складні. Оскільки існує безліч ароматів CQRS, тобто прогнозування подій, які в деяких районах можуть розглядатися як складні, а в інших - тривіальні.
Олексій Зімарьов

3

CQRS не є заміною один для одного Репозиторіям, саме тому, що це складна, дорога модель, яка корисна лише в деяких випадках.

Ось що Уді Дахан має сказати на заслугу:

Більшість людей, що використовують CQRS (і події Sourcing теж), не повинні були цього робити.

[...]

Вибачте, що більшість зразкових програм, які ви побачите в Інтернеті, показують, що CQRS є архітектурно неправильними. Я б також був дуже обережним до рамок, які направляють вас до сукупної кореневої моделі CQRS у стилі сутності.

( джерело )

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

[...] Ви повинні бути дуже обережними щодо використання CQRS . Багато інформаційних систем добре поєднуються з поняттям інформаційної бази, що оновлюється так само, як і читається, додавання CQRS до такої системи може додати значної складності.

( джерело )

Нарешті, Грег Янг:

CQRS можна назвати архітектурною схемою.

[...]

Це дуже важливо, щоб зрозуміти, що більшість архітектурних моделей не добре застосовувати скрізь. Якщо ви бачите архітектурні зразки в архітектурному керівництві, напевно, у вас є проблеми

[...]

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

( джерело )

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.