Денис Цветцих - Rich Model и Anemic Model: враги или друзья

Поделиться
HTML-код
  • Опубликовано: 28 сен 2024
  • Подробнее о конференции DotNext: jrg.su/3WmFRE
    - -
    В сообществе много холиваров о том, какую модель лучше использовать - Rich или Anemic. При этом лагерь консультантов активно топит за Rich Model, а среди разработчиков популярна Anemic Model. Поговорим о модели без предрассудков и с практической точки зрения. Для начала определимся с понятиями, что принято называть терминами Rich Model и Anemic Model, по каким критериям их можно отличить. Посмотрим, стоит ли использовать две модели данных: бизнес-модель для бизнес-логики и отдельную data-модель для маппинга на базу. Увидим, какие кейсы невозможно реализовать в канонической Rich-модели. Обсудим, так ли страшна анемичная модель, как ее ругают. И придем к прагматичной модели, которая чаще всего встречается на практике.

Комментарии • 22

  • @БогданГуківський
    @БогданГуківський Год назад +10

    По DDD есть ряд замечаний.
    Делать персональные ВО для всех полей для избежания ошибочного присвоения - очевидная глупость, не знаю кто и где так советует делать. Такое имеет смысл только для ID, типов которых будет не много, а шанс на ошибку и ее критичность большие. VO прекрасное место для размещения методов валидации, которые могут быть вызваны в application слое при построении этих самых VO(например, в VO могут быть фабричные методы, порождающие этот VO на основе более примитивного типа или возвращающие ошибку валидации).
    О том, что инфраструктура хранения плохо работает с ВО - если говорить о ORM типа EF, да, ИНОГДА бывает сложновато, но всегда решаемо. Да и хранилище не всегда relational database за EF, это может быть relational database без EF, с EF и отдельной persitence моделью, document DB, kev-value db или вовсе event store, где такой проблемы может и не быть или она уже и так решается иным образом.
    По агрегатам - задача агрегата определить границы строгой консистентности. Что с агрегатом, что без - исполнения этого бизнес требования по строгой консистентности несет неизбежные расходы по производительности.
    С примера по заказу: если смена одного orderItem не требует обновления всего заказа или позволяет это сделать с eventual consistency - то границы агрегата с примера выбраны неверно. Если не позволяет - то подход с обновлением одного orderItem принесет когда-то кому-то баг и создаст уязвимость вроде покупки 1М товаров по стоимости одной штучки)). Вероятно, понимание автором концепции агрегата искажено, если возникает постоянное желание как-то их частично редактировать, или редактировать несколько в одной транзакции. События - это часть агрегата (тот же подход event sourcing, сохраняет только эту часть, так как состояние можно восстановить), по этому их сохранения в одной транзакции с состоянием не нарушает это правило, а наоборот его подтверждает. Вся пляска с Outbox - проблема инфраструктуры, а не домена, вызванная желанием хранить состояние и события в разных хранилищах, между которыми нет стандартного механизма распределенных транзакция.
    Пример с патчем крайне странная вещь. Если в домене есть понятия установки свойств моделируемой сущности, то ничто не мешает сделать их сеттеры публичными. DDD не запрещает публичные сеттеры, просто не так уж и часто в домене есть операция - установить свойство. Обычно домен имеет более специальные операции, следствием которых есть изменения значения свойств модели. Так же модель может и метод ApplyPath поддерживать, и это никак не нарушит инкапсуляцию, если и правда в данной предметной области есть такое действие. Это не запреты в DDD, это маркеры для обращения внимания, ибо ЧАСТО наличие такого говорит о слабом понимании предметной области и больших серых зонах, которые закрываются в такой способ и за что будет позже расплата. Ну или о слишком простой модели, где DDD просто не нужно, как и разработка отдельного программного продукта, и где задачу проще решить универсальной noCode платформой.
    Главный мой совет - не стоит заниматься Карго DDD, продолжая мыслить на Transaction Script манер. Если TS позволяет решать ваши задачи хорошо - вам не нужен DDD. DDD- это инструмент борьбы с доменной сложностью, для применения которого должна быть эта самая сложность и умение его применять у ВСЕЙ команды проекта. Применять разные практики с DDD частично - также возможно, главное делать с умом. Никто не запрещает применять стратегические паттерны вроде единого языка, ограниченных контекстов и способов их интеграции и при этом внутри контекста не применять тактические паттерны и использовать TS подход. И наоборот, никто не мешает в монолитном приложении использовать агрегаты и ВО. Главное понимать суть этих шаблонов и применять их там, где они уместны.

  • @smilesrg
    @smilesrg 11 месяцев назад

    Спасибо, провели хороший ресёрч, очень ценный доклад!

  • @VoroninPavel
    @VoroninPavel Год назад

    JsonPatch - это про REST, но DDD больше про команды, а не про ресурсы. Если клиенту приехала DTO-портянка заказа со всеми строками (read model), это не значит, что обязан существовать endpoint, который точно такую же DTO ест.

  • @VoroninPavel
    @VoroninPavel Год назад +6

    Пример с жирным аггрегатом в виде заказа как бы намекает на то, что аггрегат, возможно, выбран не самым правильным образом. У аггрегата лишь одна задача - обеспечение транзакционной целостности множества сущностей. Если можно изолированно менять строку заказа, то аггрегат - это именно она. А дальше уже начинаются пляски, если существуют бизнес-правила для всего заказа целиком. Тут придется выбирать, или все-таки считать аггрегатом весь заказ и решать проблемы производительности иными способами, или городить огород с сагами, синхронной обработкой событий, откатом изменений (а это сложно, дорого, и вся операция все равно будет длинной во времени).
    По мне уж лучше медленный, но корректный код, чем быстрый, но с шансом, что он какие-то бизнес инварианты пропускает.
    P.S. Спасибо за до клад. Есть над чем подумать. ;-)

  • @MaxRozov
    @MaxRozov Год назад +3

    Ну как-то... не знаю. Постоянно возникает ощущение, что любую из двух моделей (anemic vs rich) критикуют люди, плохо в ней разобравшиеся. Ибо обе - прекрасно работают в прямых руках.
    Например - критика value objects на основе тезиса о "невозможности фильтрации по полям" вроде как упускает реальные возможности EF, в частности - OwnsOne, всё там можно.
    Критика агрегатов на основе тезиса "в заказе слишком много позиций" как бы сходу ставит под сомнение И логику выделения такого "жирного" Агрегата вообще И понимание докладчиком самой сути этого паттерна, а суть в том, что если "просто изменить одну позицию заказа", то у вас может "просто отъехать вычисление скидки, кешбека и т.п.".
    Если Order и его OrderItem-ы не атомарны, так и нефиг их объединять в один Агрегат.
    В целом, современная разработка в рамках DDD на тактическом уровне - это постоянное балансирование между атомарностью Агрегата и распределённостью логики посредством Domain Events (с синхронизацией изменений различных агрегатов посредством транзакций).

  • @nikitagrishin5891
    @nikitagrishin5891 Год назад +2

    Позиция и изыскания автора объясняются тем что он сразу загнал себя в угол одной универсальной моделью без разделения на business entity и data entity и попытался на нее натянуть все консёрны одним махом

  • @DzhigurdaAnton
    @DzhigurdaAnton Год назад +2

    Прошу Автора посмотреть доклад Владимира Хорикова про Валидацию в ДДД про объекты значения, там вопрос на 27 минуте в этом видео полностью и детально рассмотрен. Я думаю автор получит удовольствие от просмотра и ответы на вопросы заявляенные в этом видео.

  • @bananasba
    @bananasba Год назад +1

    Нельзя сидеть на двух стульях, а именно пытаться сделать вид, что на сущностях из базы данных можно реализовать ддд.

    • @БогданГуківський
      @БогданГуківський Год назад

      Если и возможно - то только при таком низком уровне сложности модели, где и без ДДД можно, а скорее, и вовсе без написания кода решить эту задачу в раз 10 дешевле используя (no/low)Code сервис.

  • @horsehorse9399
    @horsehorse9399 Год назад +2

    Я как-то упустил момент во времени: когда это публичный сеттер стал нарушением инкапсуляции? Свойства для инкапсуляции изначально и задуманы (это же просто 2 метода, ну и + поле под ними, если это автопроперти). Звучит как какой-то нонсенс. Если нужно задать значение извне, то он обязан был публичным, не нужно для него городить отдельный метод (он сам собой именно им и является).

    • @БогданГуківський
      @БогданГуківський Год назад +1

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

  • @DimonSmart
    @DimonSmart Год назад +1

    Мне нравится тема разделения модели и поведения. И предложенный способ валидации на уровне проекта (чтобы в сеттеры модели лазить только из одного проекта) выглядит очень красиво. А вариант когда модель нашпиговывают всеми имеющими отношение к модели методами выглядит не как Rich а скорее как Big Ball of mud. Особенно это заметно присложных многострочных методах

  • @DzhigurdaAnton
    @DzhigurdaAnton Год назад

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

  • @VoroninPavel
    @VoroninPavel Год назад

    Проблема в том, что инкапсуляция - контекстное понятие, но языки программирования такую штуку практически никак не поддерживают. Тот же ORM болт кладет на инкапсуляцию и лезет в private члены entity или использует private конструктор.

  • @NoldoWalker
    @NoldoWalker Год назад

    Очень комплексно рассказано, спасибо!

  • @bananasba
    @bananasba Год назад

    Вода, кругом вода, больше водыыы

  • @AlexanderRadchenko
    @AlexanderRadchenko Год назад

    По имени!

  • @native-nature-video
    @native-nature-video Год назад

    Спасибо за видео!!!

  • @alexanderzakharov-u1b
    @alexanderzakharov-u1b Год назад

    Мне одному кажется, что все проблемы Rich-модели были бы решены, если в c# добавить понятие дружественных классов, которое есть в с++?

    • @maxarshinov
      @maxarshinov 3 месяца назад +1

      Они уже есть. Nested классы имеют доступ к private родителя.

    • @АлександрКубит-з2е
      @АлександрКубит-з2е 2 месяца назад

      Вероятно вы ищите способ как поделиться внутренней реализацией, с определённым классом, это довольно просто можно сделать с помощью делегатов