Должен ли я игнорировать руководство и не помещать проверку в объекты команд?

Я использую CQRS. Везде, где я читал, мне говорят, что логика проверки должна быть помещена в объекты команд. Например, см. Эту ссылку: https://lostechies.com/jimmybogard/2016/04/29/validation-inside-or-outside-entities/

См. Команду ниже (взято из ссылки):

public class ChangeNameCommand { 
   [Required] 
   public string FirstName { get; set; } 
   [Required] 
   public string LastName { get; set; } 
 } 

и бизнес-объект ниже (также взят из ссылки - обратите внимание, что я изменил параметр, переданный конструктору Customer, с класса на интерфейс):

public class Customer 
{ 
   public string FirstName { get; private set; } 
   public string LastName { get; private set; } 

   public void ChangeName(IChangeNameCommand command) { 
     FirstName = command.FirstName; 
     LastName = command.LastName; 
   } 
 } 

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

public class ChangeNameCommandWithoutValidation : IChangeNameCommand { 
   public string FirstName { get; set; } 
   public string LastName { get; set; } 
 } 

а затем передать команду (без проверки) объекту домена. В этом случае я считаю, что объект домена не контролирует, что ему передается?

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

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

Я думаю, что вам мощь лучше иметь обработчик команд, обрабатывающий конкретную команду. Затем вы можете выполнить проверку команды там и после этого вызвать агрегат или объект для выполнения логики домена. Таким образом, у вас может быть красивый и понятный способ использования. Я не сторонник передачи команд прямо в агрегаты, поскольку они должны воздействовать на самих себя и на свои соответствующие объекты, которых они должны защищать, и так далее. Но в целом, здесь нет серебряной пули, делайте то, что ваша команда / партнеры решают и могут работать / решать.

kayess 08.06.2018 13:46

@kayess, означает ли это, что класс модели предметной области может быть недопустимым (если разработчик забыл или случайно удалил проверку из команды)?

w0051977 08.06.2018 13:48

Я так не думаю, у вас должны быть единичные / интеграционные / какие-либо другие тесты для вашей SUT, которые будут нести ответственность за то, чтобы такие несчастные случаи не могли произойти. Но, как гласит моя любимая цитата по этому поводу: «нет защиты от чуши человеческой». Также вы можете выполнять валидацию в стиле АОП, например иметь декоратор ... Другой способ подумать об этом, вы можете проводить обзоры кода и т.д., но это выходит из-под контроля, поскольку мы становимся слишком широкими.

kayess 08.06.2018 13:50

Я не эксперт в CQRS, но мне кажется странным, что вы используете интерфейс для команд. Есть ли вообще смысл иметь несколько реализаций для одного командного интерфейса? Думаю, ваш пример с ChangeNameCommandWithoutValidation показывает, что это не так. И менее "зло" пример был бы IChangeNameCommand со вторым именем. Ваш объект Customer примет такую ​​команду, но на самом деле не может ее обработать.

Dirk 08.06.2018 13:50

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

kayess 08.06.2018 13:53

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

w0051977 08.06.2018 13:56

Это дело вкуса. Но вам не нужно проверять события, поскольку они являются результатом логики вашего домена, которая (должна быть) защищена ранее проверенной проверкой. События - это просто результаты некоторой уже произошедшей логики, сообщающей подписчикам, что произошло это. По крайней мере, так я это вижу, оставьте это здесь, чтобы посмотреть, как поступят другие.

kayess 08.06.2018 13:58

@kayess, вы говорите, что проверка должна быть продублирована в модели команды и домена?

w0051977 08.06.2018 14:00

Нет. Я говорю, что вы должны проверять все входящие данные. Где вы это сделаете, действительно зависит от вас, будь то начальная проверка в обработчике команд и некоторая проверка, ориентированная на домен, в объекте домена. Никто не будет заставлять вас делать это так или иначе ... :) И эти блоги берите как примеры, а не высеченные на камне правила.

kayess 08.06.2018 14:01

@kayess, я считаю, что проверка должна выполняться на границах, и, похоже, есть две границы, т.е. по команде и на мероприятии. Я стараюсь следовать принципу наименьшего удивления.

w0051977 08.06.2018 14:04

Позвольте нам продолжить обсуждение в чате.

kayess 08.06.2018 14:05

@kayess, я задал следующий вопрос, если вы хотите взглянуть: softwareengineering.stackexchange.com/questions/372338/….

w0051977 10.06.2018 16:17
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
12
183
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Несколько мыслей:

  • Сообщение в блоге, на которое вы ссылаетесь, сбивает с толку, потому что оно приравнивает валидацию к инвариантам.

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

    С другой стороны, вид валидности, о котором говорят образцы в сообщении Джимми Богарда, находится на границе между валидностью домена и валидностью пользовательского ввода. Я бы не стал твердым правилом ставить такую ​​проверку на ту или иную сторону. Хотя правомерно считать, что это действительно работа для команды, с некоторыми системами типов вы можете идеально кодировать такого рода ненулевые ограничения в типах свойств сущности, и было бы стыдно не воспользоваться этой бесплатной дополнительной корректностью.

  • Как было сказано в комментариях, размещение интерфейса поверх команды кажется странным.

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

Спасибо. Я полагаю, вы говорите, что объект действителен, если соблюдаются все его инварианты. Я полагаю, вы также говорите, что сущность может быть действительной с такими данными: ID = Guid.Empty, Name = "", Age = 0 и т. д. Верно?

w0051977 08.06.2018 15:06

Как я уже сказал, действительный - это загруженный термин. Для определения валидности, ориентированного на предметную область, да. Для определения, ориентированного на ввод пользователя, нет.

guillaume31 08.06.2018 15:18

Я только что нашел здесь ваш ответ: stackoverflow.com/questions/30190302/…. Мне нравится комментарий, в котором говорится: «вы используете проверку, чтобы убедиться, что входные данные имеют допустимый формат, а затем бизнес-правила решают, как / если входные данные изменяют модель». Я интерпретирую это как означающее, что проверка выполняется командой, а инварианты рассматриваются в модели предметной области. +1 за другой ответ.

w0051977 08.06.2018 15:25

Например, допустим, у клиента есть свойство Customer.Offer. Предложение создается, если Клиент старше 21 года и потратил 1000 фунтов стерлингов. В этом случае проверка (в команде) будет проверять, что возраст больше или равен 0 и что расходы больше или равны 0, а модель предметной области будет проверять, что клиент старше 21 года и потратил 1000 фунтов стерлингов. или более перед назначением оферты. Это правильно?

w0051977 08.06.2018 15:29

Я думаю, пока вы относитесь к ним как к примерам, а не к каменным правилам вроде «> 0 всегда означает проверку команды вне зависимости от контекста» ;-)

guillaume31 08.06.2018 15:59

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

guillaume31 08.06.2018 16:02

Прежде чем я отвечу и проведу черту под этим - «> 0 всегда означает проверку команды вне зависимости от контекста». Если есть контекст, то я считаю, что он будет специфичным для предметной области и должен появиться в модели предметной области?

w0051977 08.06.2018 16:10

Это могло быть как угодно. В зависимости от контекста есть домен> 0 и аппликативный> 0. Используйте здравый смысл, чтобы принять решение;)

guillaume31 08.06.2018 16:25

Я задал следующий вопрос, если вы хотите взглянуть: softwareengineering.stackexchange.com/questions/372338/…

w0051977 10.06.2018 16:18

Другие вопросы по теме