{
    "version": "https:\/\/jsonfeed.org\/version\/1.1",
    "title": "Дима пишет | Дмитрий Смотров: заметки с тегом CQRS",
    "_rss_description": "backend python fastapi django rabbitmq kafka postgresql sqlalchemy",
    "_rss_language": "ru",
    "_itunes_email": "",
    "_itunes_categories_xml": "",
    "_itunes_image": "",
    "_itunes_explicit": "",
    "home_page_url": "https:\/\/dimasmotrov.ru\/tags\/cqrs\/",
    "feed_url": "https:\/\/dimasmotrov.ru\/tags\/cqrs\/json\/",
    "icon": "https:\/\/dimasmotrov.ru\/pictures\/userpic\/userpic@2x.jpg?1718470292",
    "authors": [
        {
            "name": "Дима Смотров",
            "url": "https:\/\/dimasmotrov.ru\/",
            "avatar": "https:\/\/dimasmotrov.ru\/pictures\/userpic\/userpic@2x.jpg?1718470292"
        }
    ],
    "items": [
        {
            "id": "12",
            "url": "https:\/\/dimasmotrov.ru\/all\/cqrs-3\/",
            "title": "CQRS (3)",
            "content_html": "<p><b>Когда полезно использовать<\/b><\/p>\n<p>— В сложных доменных областях. Использование подхода позволит снизить сложность каждого конкретного контекста программы.<br \/>\n— Если в системе сильно различается частота запросов на чтение и запросов на БЛ составляющие системы. Например можно разместить Command & Queries в разных процессах, что позволит горизонтально масштабировать Queries часть системы, так как обычно запросов на чтение сильно больше запросов на запись.<br \/>\n— Если ваша система спроектирована по принципу EDA(Событийно-ориентированная архитектура). Событию системы соотносится конкретная модель данных. Позволяет БЛ не вытекать за пределы обработчика события.<br \/>\n— Когда вы собираетесь разделить базу данных на БД для записи и БД для чтения. Однако следует учитывать, что при разделение БД так же встает вопрос о конечной согласованности данных в базах.<\/p>\n<p><b>Когда использование не даст преимуществ<\/b><\/p>\n<p>— Модели Command & Queries совпадают. В таких случаях лучше использовать совместную(единую) модель.<br \/>\n— В случае, если доменная область неверно выделена в системе, то использование CQRS только запутает и без того слабо структурированный код.<\/p>\n",
            "date_published": "2024-12-06T19:48:09+03:00",
            "date_modified": "2024-12-06T19:48:05+03:00",
            "tags": [
                "CQRS",
                "АрхитектураПО",
                "Разработка"
            ],
            "_date_published_rfc2822": "Fri, 06 Dec 2024 19:48:09 +0300",
            "_rss_guid_is_permalink": "false",
            "_rss_guid": "12",
            "_e2_data": {
                "is_favourite": false,
                "links_required": [],
                "og_images": []
            }
        },
        {
            "id": "11",
            "url": "https:\/\/dimasmotrov.ru\/all\/cqrs-2\/",
            "title": "CQRS (2)",
            "content_html": "<p>Вернемся к основной теме<\/p>\n<p>В проектах часто вижу, что ORM модель сущности используется во всех контекстах(доменных областях, которые по сути есть в программе, но по факту никто их явно не выделял) системы:<br \/>\n— как выходное отображение для ответа API;<br \/>\n— как DTO между разными модулями;<br \/>\n— для модуля работы с БД(orm модель по логике должно существовать только в рамках этого модуля);<br \/>\n— как модель для формирования тела сообщения в очередь сообщений.<\/p>\n<p>В каждом контексте из перечисленных выше используется одна и та же модель, несмотря на то, что данные модели избыточны в каждом случае примерно на 40-50%(цифры вывел эмпирически, сухой статистики у меня нет, к сожалению). Имеем жирную модель данных на все случаи жизни.<\/p>\n<p>CQRS предоставляет разделение жирной модели на Command model(модель для работы БЛ: создание, обновление, связывания с моделями других сущностей, и т. д.) & Query Model(отображаемая пользователю в запрашиваемом домене).<\/p>\n<p>Названия украдены из концепции Command Query Separation (<a href=\"https:\/\/martinfowler.com\/bliki\/CommandQuerySeparation.html),\">https:\/\/martinfowler.com\/bliki\/CommandQuerySeparation.html),<\/a> ключевая идея которой в том, что требуется разделять действия над моделью на две категории:<br \/>\n— Queries — возвращает результат, но не меняет состояние системы(методы без сторонних эффектов)<br \/>\n— Command — Изменяет состояние системы, но не возвращает состояние системы.<\/p>\n<p>Для каждой категории действий над сущностями приложения мы имеем конкретные модели. Если меняется логика создания сущностей — мы актуализируем модель для Command категории. Если меняется логика отображения пользователю — мы актуализируем модель для Query.<\/p>\n<p>Для каждой категории действии может быть несколько моделей с более конкретной направленностью под каждую доменную область(например списочная и информационная модель из примера в прошлом посте).<\/p>\n",
            "date_published": "2024-12-06T19:47:19+03:00",
            "date_modified": "2024-12-06T19:47:14+03:00",
            "tags": [
                "CQRS",
                "АрхитектураПО",
                "Разработка"
            ],
            "_date_published_rfc2822": "Fri, 06 Dec 2024 19:47:19 +0300",
            "_rss_guid_is_permalink": "false",
            "_rss_guid": "11",
            "_e2_data": {
                "is_favourite": false,
                "links_required": [],
                "og_images": []
            }
        },
        {
            "id": "10",
            "url": "https:\/\/dimasmotrov.ru\/all\/cqrs-1\/",
            "title": "CQRS (1)",
            "content_html": "<p>Или же Command Query Responsibility Segregation<\/p>\n<p>Вообще, идея концепции состоит в разделение моделей данных на модели для чтения и на модели для записи. Но, как мне кажется, лучше смотреть чуть шире:<br \/>\nкаждый контекст системы должен обладать своим собственным состоянием, на каждое состояние необходима своя модель, содержащая информацию исключительно для работы конкретного контекста.<\/p>\n<p>Например: представим главную страницу сайта для продажи товаров. На этой странице отображена минимальная информация по товарам — фотография, название, цена. Но при переходе на страницу конкретного товара мы увидем более подробное описание товара, помимо цены, фотографии и названия — остаток на складе, производитель, страна поставки сырья и тому подобное.<\/p>\n<p>Логично, что для отображения товара на главной странице не нужна вся информация о товаре — ее мы посмотрим детально при желании. Отсюда напрашиваются две модели для сущности товара — списочное отображение(минимум данных) и информационное представление(максимум данных).<\/p>\n<p>Конечно можно использовать только модель для информационного отображения, ведь в ней находятся все данные о товаре, а на главной странице мы можем отображать только необходимый минимум. Но зачем нам кратно увеличивать трафик и сокращать скорость работы главный страницы, когда мы можем этого не делать? К тому же известно, чем больше кода, тем больше вероятность ошибиться: например использовать неверное поле для отображения, допустим вместо title использовать description. Пример смешной и легкий, но если подумать, то сокращение полей в модели снижает риск ошибки, так как поля description в модели не будет вовсе, на главное странице оно не нужно.<\/p>\n<p>По аналогии с главной страницы товаров, разделение большой(«жирной») модели на более конкретизированные для текущего контекста выполнения позволяет сделать код безопаснее — лишние данные отсутствуют, мы просто обречены использовать именно то, что нужно :)<\/p>\n",
            "date_published": "2024-11-14T23:50:02+03:00",
            "date_modified": "2024-11-14T23:49:45+03:00",
            "tags": [
                "CQRS",
                "АрхитектураПО"
            ],
            "_date_published_rfc2822": "Thu, 14 Nov 2024 23:50:02 +0300",
            "_rss_guid_is_permalink": "false",
            "_rss_guid": "10",
            "_e2_data": {
                "is_favourite": false,
                "links_required": [],
                "og_images": []
            }
        }
    ],
    "_e2_version": 4134,
    "_e2_ua_string": "Aegea 11.3 (v4134)"
}