Архитектура приложений и фрактал дизайна
Итак, когда мы говорим об «архитектуре» в мире ИТ, мы можем говорить о любой из множества вещей, стоит четко указать, какую из них вы обсуждаете. Например, если я вступаю в дискуссию по архитектуре предприятия, рассказывая о CQRS с Event Sourcing, велика вероятность, что я зря потрачу время всех.
CQRS с Event Sourcing — это архитектура приложения, которая информирует меня о том, как я создаю конкретное бизнес-приложение/сервис. Конечно, мое предприятие может внедрить CQRS, но если оно это сделает, то сделает это как сквозную архитектуру приложений.
Когда мы говорим об архитектуре приложений, какой бы тип мы ни использовали, разумно помнить о фрактале дизайна. Возьмем CQRS с Event Sourcing (что-то, что я сейчас использую, поэтому я могу с готовностью рассказать об этом). Design Fractal говорит, что я забочусь о своих принципах SOLID как на уровне метода, так и на уровне предприятия. Но как это относится к CQRS?
Во-первых, краткое введение в CQRS с Event Sourcing, потому что не все об этом знают.
CQRS — это «разделение ответственности за запросы команд». Это означает, что я использую два разных канала при доступе к своим предметным объектам (да, это чаще всего используется в парадигме Domain Driven Design). Одним из них является командный канал, который обрабатывает мои операции CRUD и бизнес-логику. Другой — это канал запроса, который предоставляет копии объектов домена только для чтения, в основном для использования за пределами домена.
Event Sourcing — это отдельная, но очень совместимая идея, согласно которой мои объекты предметной области на самом деле являются просто суммой событий, которые привели к созданию их текущего состояния. Таким образом, вместо обязательного хранения моей корзины покупок как таковой я храню события корзины с некоторым идентификатором агрегации. Затем, когда я готов что-то сделать с корзиной — скажем, превратить ее в фактический заказ и оплатить — я обрабатываю события, чтобы определить конечное состояние объекта корзины.
Существует множество источников по этим темам, как по отдельности, так и в целом, и я настоятельно рекомендую вам провести по ним дополнительные исследования. Они представляют собой довольно мощную комбинацию.
Итак, с учетом этого, как мы можем применить SOLID к CQRS с помощью Event Sourcing? Давайте взглянем.
S – единая ответственность
Это встроено в CQRS: командный канал отвечает только за обработку команд. Обработчик событий (который, скорее всего, находится внутри командного канала) отвечает только за обработку событий для оценки состояния объекта. Канал запросов отвечает только за обслуживание запросов только для чтения.
Но он становится глубже – и более общим. Предположительно, у меня есть несколько вещей, которые могут случиться с моим объектом. Возьмем, к примеру, заявку на получение кредита. Я могу дополнить его информацией, я могу изменить информацию, я могу оценить ее полноту в любой момент, я могу отправить ее на андеррайтинг и так далее. Каждый из них проходит через один и тот же компонент? Конечно нет. Вместо этого у меня может быть несколько небольших компонентов, каждый из которых отвечает за обработку определенной команды или определенного набора тесно связанных команд. У меня могут быть компоненты, которые составляют другие компоненты. Очень быстро я выгляжу как система Актера и/или микросервисы — и то и другое становится возможным на достаточно высоких уровнях сложности — но мне не обязательно заходить так далеко.
О – открыт/закрыт
Это также входит в состав торта CQRS. Предоставляя копии только для чтения через канал запроса, потребители могут писать любые методы, которые им нужны, в этих копиях только для чтения, расширяя их по мере необходимости, в то время как мой предметный объект и логика остаются полностью под моим контролем.
Другие архитектуры могут подойти к этому по-другому. Некоторые будут делать это просто за счет управления кодом или безопасности кода — только код в домене приложения может получить доступ к определенным членам. Некоторые могут не решать это напрямую каким-либо осмысленным образом, что делает более обязательным рассмотрение этого в нашем дизайне.
L — Замена Лискова
Этот немного сложнее, но он восходит к идее компонентов, о которой я упоминал ранее. Если у меня есть много компонентов, которые обрабатывают определенные команды, они должны, по крайней мере, иметь общий интерфейс. Сами команды должны иметь общий интерфейс. Благодаря этому я могу быстрее сочинять и могу обрабатывать большие группы команд, событий или компонентов несколькими способами, если мне это нужно. Кроме того, если у меня есть определенный компонент для *большинства* моих объектов, но я знаю, что некоторые конкретные объекты должны будут заменить свое собственное поведение, я могу иметь несколько компонентов, которые реализуют один и тот же интерфейс (что приводит нас к D в SOLID), и по-прежнему передавать эти компоненты, как если бы они были базовой реализацией, когда это необходимо.
Это вообще не относится к CQRS, но CQRS делает это довольно легко, если мы добавим идею обработки на основе компонентов.
I — Разделение интерфейса
Опять же, это не относится к CQRS. Используя компонентный подход, я могу иметь столько конкретных интерфейсов, предоставляющих определенные функции, сколько мне нужно.
D — Инверсия зависимости
Как упоминалось в разделе «Замена Лискова», наш компонентный подход к фактической обработке команд/событий позволяет нам обрабатывать большую часть функций через интерфейс. Это означает, что данный координирующий компонент не должен быть непосредственно осведомлен о каких-либо специализированных компонентах, пока эти компоненты имеют общий интерфейс с более общими версиями.
Теперь CQRS с Event Sourcing сам по себе не гарантирует ничего из этого и может или не может быть реализован таким образом, который совместим с Design Fractal. Действительно, когда мы говорили о LID SOLID, ни один из них не имеет прямого отношения к CQRS — вы можете реализовать их или нет, но при этом оставаться в рамках шаблона. И наоборот, фрактал дизайна может информировать любую модель или шаблон архитектуры приложений. Когда мы говорим об архитектуре приложений, мы должны помнить о фрактале дизайна. Если мы обнаружим, что отклоняемся от этих принципов, нам может потребоваться рассмотреть возможность внесения изменений.