Объекты-значения в CQRS - где использовать

Допустим, у нас есть архитектура, вдохновленная CQRS, с такими компонентами, как команды, модель домена, события домена, DTO модели чтения.
Конечно, мы можем использовать объекты значений в нашей модели домена. У меня вопрос, должны ли они также использоваться в:

  1. Команды
  2. События
  3. DTO

Я не видел примеров, где объекты-значения (VO) используются в упомянутых выше компонентах. Вместо этого используются примитивные типы. Может быть, это просто упрощенные примеры. В конце концов, я понимаю использование ВО в DDD как связующее звено для всего приложения.

Моя мотивация:

Команды.
Допустим, пользователь отправляет форму, содержащую поля адреса. У нас есть объект значения адреса для представления этой концепции. Создавая команду в клиенте, мы все равно должны проверять вводимые пользователем данные, и когда они правильно сформированы, мы можем создать объект Address прямо здесь и инициализировать Command с его помощью. Я не вижу необходимости делегировать создание объекта Address обработчику команд.

События предметной области.
Модель предметной области уже работает в терминах объектов-значений, поэтому, публикуя события с ВО вместо их преобразования в примитивные типы, мы можем избежать некоторого кода сопоставления. Я почти уверен, что в этом случае можно использовать голосовые вызовы.

DTO.
Если наши DTO на стороне запроса могут содержать объекты значений, это обеспечивает некоторую гибкость. Например, если у нас есть объект Money, мы можем выбрать, отображать ли его в евро или долларах США, нет необходимости изменять модель чтения.


person driushkin    schedule 02.02.2011    source источник
comment
Поразмыслив над этим некоторое время, я пришел к выводу: иметь объекты с богатым поведением в событиях просто невозможно, поскольку они должны представлять исторические данные, а сегодня у нас нет возможности сериализовать поведение. Что касается команд и моделей чтения DTO, это может сработать, и мне до сих пор неясно, является ли соединение, которое оно вводит, приемлемым или нет (в любом случае, это больше о том, `` должны ли уровни домена и представления ссылаться на одну и ту же реализацию Money VO '' а не «должен ли TransferMoneyCommand содержать Money VO или MoneyDTO»).   -  person driushkin    schedule 04.04.2011
comment
Аналогичное обсуждение происходит в репозитории PHPDDD. Не стесняйтесь присоединиться: github.com/webdevilopers/php-ddd/issues/14   -  person webDEVILopers    schedule 03.02.2019


Ответы (5)


Хорошо, я передумал. В последнее время я много пытался иметь дело с голосовыми операторами, и после просмотра этого http://www.infoq.com/presentations/Value-Objects-Dan-Bergh-Johnsson он прояснил для меня несколько вещей.

Команды и событие - это сообщения (а не объекты, объекты - это данные + поведение), в некоторых отношениях они очень похожи на DTO, они передают данные о событии и сами не инкапсулируют никакого поведения.

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

Команды и события передают информацию в домен и из него соответственно, но сами по себе не инкапсулируют какое-либо поведение. С этой точки зрения пропускать ВО внутри них кажется неправильным и, возможно, нарушением границ контекста.

Перефразируя Орена (хотя он имел в виду nHibernate и WCF), «не отправляйте свой домен по сети». http://ayende.com/Blog/archive/2009/05/14/the-stripper-pattern.aspx

Если вы хотите передать объект-значение, я предлагаю вместо этого передать необходимые атрибуты, необходимые для воссоздания VO внутри них.

Исходный текст (для потомков):

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

При этом объект значения представляет такие понятия, как, например, цвет. У вас нет зеленого цвета, вы зеленый или нет. Кажется, что по сути нет ничего неправильного в команде, сообщающей вам, что вы зеленый, передавая это.

Чтение главы DDD о шаблоне агрегированного корня достаточно хорошо объясняет сущности и объекты-значения, и ее стоит прочитать несколько раз.

person Chris Nicola    schedule 07.02.2011
comment
Я думаю, что с чистой точки зрения DDD совместное использование VO - это нормально, но с точки зрения cqrs это может вызвать некоторые технические проблемы, такие как управление версиями событий, если применяется Event Sourcing. И тогда возникает естественный вопрос, действительно ли это чисто техническая проблема или это что-то по сути неправильное во всей идее. - person driushkin; 09.02.2011
comment
Из книги DDD я понял, что, хотя агрегированные корни являются владельцами своих соответствующих сущностей и объектов значений, они могут временно передавать ссылку на эти объекты. Единственная цель агрегированного корня - определить транзакционные границы системы. Опять же, я могу неправильно истолковать некоторые из них и, как всегда, YMMV. Хотя было бы определенно плохо сериализовать объект как часть события, я не вижу никаких проблем для ВО, поскольку они должны представлять истинное неизменное значение. - person Chris Nicola; 10.02.2011
comment
Объекты-значения совсем не похожи на DTO. Они являются представлением предметной области и [...] обладают богатым поведением, как и все другие представления предметной области. Я категорически не согласен с последней частью. Хотя они являются частью домена (например, определяют, что такое Address), они предназначены для одноразового использования и не связаны с каким-либо поведением. Вот почему они обычно неизменяемы, чтобы вы не захотели возиться со своим ВО. - person Dav; 27.07.2012
comment
Неизменяемость и поведение не исключают друг друга. Объекты значений, например Money или DateRange, безусловно, обеспечат некоторые связанные функции и логику, основанные на концепции предметной области, которую они представляют. Если бы это были просто данные, то достаточно было бы встроенных базовых типов. См .: martinfowler.com/eaaCatalog/valueObject.html - person Chris Nicola; 29.04.2015
comment
Вот хорошее сравнение Value Object и DTO: enterprisecraftsmanship .com / 2015/04/13 / - person Vladimir; 23.12.2015

Я говорю, что это плохая идея.

Есть причина, по которой мы не делаем то же самое с сущностями - чтобы не связывать другие части системы с доменом (в неправильных местах). То же самое верно и для объектов-значений, единственное различие между объектами-значениями и сущностями - это время жизни и владение - эти различия не влияют на то, как мы должны и не должны связываться с ними.

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

Этого следует избегать.

Используйте DTO и / или примитивы. Сопоставьте их (AutoMapper делает это в одну строку).

person quentin-starin    schedule 02.02.2011
comment
Что ж, эти ВО не принадлежали бы исключительно модели предметной области. Они будут общими знаниями для всех компонентов системы (например, сборка MyApp.Core, на которую может ссылаться кто угодно). Я думаю, что пока концепции стабильны или даже не имеют критических изменений, все должно быть в порядке. Конечно, если мы используем Event Sourcing, это загромождает наш код устаревшими концепциями, которые больше не используются, но являются частью старых событий. Так что это один недостаток, о котором я могу думать. Но все же идея иметь в приложении модуль общих концепций (таких как валюта, деньги, скорость) кажется мне очень заманчивой. - person driushkin; 02.02.2011
comment
Если они являются общими для приложений концепциями, я бы сказал, что они не столько часть домена (поскольку домен практически по определению специфичен для приложения), сколько инфраструктура или общий код. Я думал об этом конкретно о деньгах, когда отвечал. - person quentin-starin; 02.02.2011
comment
Я также считаю, что VO в CQRS - плохая идея, но тогда как мы можем инкапсулировать логику предметной области, когда агрегирование становится слишком сложным? - person Szymon Pobiega; 03.02.2011
comment
@driushkin, вы когда-нибудь приходили к выводу, как относиться к этим общим понятиям? У меня тот же вопрос, и я склоняюсь к тому, чтобы сделать DTO общей концепцией. Я знаю, что это очень старая ветка, но, возможно, вы все еще отслеживаете ее. - person Stefan de Kok; 23.02.2015
comment
То же самое и здесь @StefandeKok. Наткнулся на этот старый пост. Мне любопытно, включать ли мои команды ВО или оставлять их плоскими (примитивами). Такой сложный вызов! - person prograhammer; 16.10.2015
comment
Потому что мои ВО содержат некоторую логику проверки. Какой смысл сохранять команды примитивными, если вы просто собираетесь скопировать проверку (из ВО) и выполнить ее заранее, а затем снова, когда команда будет обработана. Пользователю не нужно ждать, чтобы узнать, что такие вещи, как адрес, телефон, электронная почта, деньги, не подтверждают ИМХО. Но я также понимаю, что это может быть негерметично. Так что непросто! - person prograhammer; 16.10.2015
comment
@prograhammer, в итоге я полностью сохранил объекты значений внутри домена. - person Stefan de Kok; 16.10.2015

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

person anavarro9731    schedule 17.02.2011

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

Я не считаю правильным помещать объекты значений в DTO также с точки зрения архитектуры. Объекты значений находятся внутри модели предметной области, в то время как упомянутые вами DTO определяют интерфейс модели. Обычно мы создаем интерфейс, чтобы отделить внешний мир от внутренней части чего-либо. Итак, в текущем случае мы добавили DTO, чтобы отделить внешний мир от объектов значений (и других вещей, связанных с моделью). После этого добавление объектов-значений в интерфейс - безумие.

Итак, вы еще не встретили это решение, потому что это антипаттерн.

person inf3rno    schedule 25.09.2014
comment
Значит, мы не должны добавлять в DTO какие-либо строки или целые числа, поскольку это также объект значения? - person Bojan Vukasovic; 21.03.2017
comment
@ bojanv55 Строки и целые числа являются примитивами, а не объектами значений. Объект Date или DateTime был бы лучшим примером. Я имел в виду, что DTO не должны передавать VO, определенные в домене. Например, в нашем домене есть голосовое сообщение, связанное с рождением кого-либо, например 1985-12-20. Если мы запрашиваем день рождения, мы должны вернуть 12-20 в DTO. Если мы запросим дату рождения, мы должны вернуть 1985-12-20 в DTO. Если мы запросим возраст, мы должны вернуть 31 год в DTO. Таким образом, DTO не будет содержать всего VO с его логикой, а будет только то представление, которое нам действительно нужно. - person inf3rno; 21.03.2017
comment
@ bojanv55 По крайней мере, так я использую DTO и VO. Этот подход работал до сих пор, но офс. Я не непогрешим. :-) - person inf3rno; 21.03.2017
comment
конечно, вы можете делать все, что хотите :) Я только что обнаружил, что использование VO в DTO помогает сохранять код более аккуратным - например, при создании событий вместо нового события (месяц, день, год) я могу сказать новое событие (День рождения). Кроме того, поскольку события являются частью домена, имеет смысл использовать там ВО ... - person Bojan Vukasovic; 21.03.2017
comment
@ bojanv55 При желании вы можете использовать обычный объект Date в своем DTO. DTO не обязательно должен быть плоским. Все это касается создания интерфейса из DTO, чтобы отделить внешнюю часть домена от внутренней части домена. Агрегаты, сущности, объекты значений находятся внутри домена, а команды и события являются частью интерфейса домена. Таким образом, внешний мир не будет зависеть от внутреннего (агрегатов, сущностей, VO), только от интерфейса (DTO). Вы следуете той же концепции в меньшем масштабе, определяя интерфейсы и классы ... - person inf3rno; 21.03.2017

Объекты-значения являются или, по крайней мере, должны быть неизменными. После создания экземпляра со значением это значение никогда не изменится в течение всего времени существования объекта. Таким образом, передача VO в качестве данных в DTO (например, Events) не должна быть проблемой, поскольку все, что вы можете с ними делать, - это получать их значение. В лучшем случае их значение в другом представлении, таком как toString(), в отличие от исходного getValue(), которое может возвращать целое число или любое другое значение.

person Keith Mifsud    schedule 13.12.2019