Как стать автором
Обновить

Комментарии 10

Все круто. Только еще мапить в промежуточный формат типа json или xdto и уже их отправлять в зеленый слой и получать оттуда. А то как-то связанность большая между элементом кода struct и внешним миром.

Если под маппингом имеется в виду Домен <-> Слой приложение (Handler, Endpoint, Controller, RPC, CLI-command и другое),
То слой приложение будет отдавать ответ в нужном виде и формате (json, xml и др.) или вы предлагаете что данные из Домена можно сразу в json положить и отдать пользователю?

Если я неправильно поняла о каком именно маппинге говорится, уточните пожалуйста)

Ну вот и в БД также. И из БД.

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

Очень сильно упрощает работу разделение моделей получения данных и агрегата изменения данных.

Я не очень понимаю как организовать взаимодействие разных контекстов. Например такая ситуация:

У пользователя есть личный кабинет, он может в личном кабинете запросить счет.

У бухгалтерии тоже есть личный кабинет, в котором она видит запросы счетов от пользователей и как-то их обрабатывает.

В данном случае, "запрос счета" у пользователя и "запрошенный счет" у бухгалтерии - это разные сущности? И каким образом "запрос счета" превращается в "запрошенный счет"? Должен ли пользователь знать о бухгалтерии и дергать в ней какой-то метод, чтобы запросить счет?

Мне кажется, что тут недостаточно исходных данных для точного ответа, потому что возможны разные сценарии в зависимости от процессов и архитектуры.

>>  "запрос счета" у пользователя и "запрошенный счет" у бухгалтерии - это разные сущности?

Скорее да, у вас может может быть целый ворох действий по постановке и выполнению формирования счета для пользователя через какой-нибудь битрикс. А для пользователя важно видеть только счетное кол-во статусов (принято, в работе, выполнено).

>> каким образом "запрос счета" превращается в "запрошенный счет"? Должен ли пользователь знать о бухгалтерии и дергать в ней какой-то метод, чтобы запросить счет?

А какая архитектура? Синхронная/асинхронная? Можно дергать метод апи, а можно в брокер события кидать.

Простой ответ: если два разных контекст - значит две разные сущности.

Но согласен с @Yakamoz, нужно больше вводных.

Поделюсь как бы я делал. При старте разработки, когда необходимости быстро получить готовый продукт и когда не понятно на сколько два счета для разных пользователей отличаются я бы делал их одной сущность.
Затем отвечал бы себе на вопрос на сколько комфортно работать с единой сущностью в зависимости от:

  1. Разные ли действия производят над сущностями пользователи и бухгалтеры?

  2. Разные ли представления счетов для бухгалтерии и пользователя?

  3. У нас несколько тех/бизнесовых команд работает над этой системой?

  4. Нужно ли нам горизонтально масштабироваться по производительности?

Чем больше, тем больше вероятность того, что их нужно делить на две.

можно использовать альтернативу — go-arch-lint

как автор тулзы, заодно порекламлю статью на хабре, как им пользоватся:
https://habr.com/ru/articles/751174/

Спасибо за статью, на личном опыте знаю как сложно сделать статью полезной и понятной большому числу людей.

В предложенном варианте есть несколько проблем, которые хотелось бы обсудить:

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

  2. Метод репозитория должен представлять транзакционную границу. Если разработчик, работая в сервисном слое, задумывается о транзакциях, значит утекла абстракция и мы уже не можем менять хранилище. Если необходимо транзакционно изменить два агрегата, то либо накосячили при проектировании, либо можно обойтись событийной согласованностью. Менеджер транзакций в ДДД говорит о проблеме.

  3. В идеале лучше иметь отдельный репозиторий на каждый агрегат и отдельно для моделей чтения данных, не смешивая команды и запросы. Паттерн CQRS хорошо подходит для подобных вещей.

  4. Нет ничего о доменных событиях, что практически является основой для общения агрегатов. Именно на событийной согласованности, в противовес транзакционной, строится независимость агрегатов. Сохранение агрегата всегда должно сопровождаться сохранением события. Паттерн outbox идеально вписываться в подобных случаях.

Мне бы еще хотелось добавить, что важно понимать как определить агрегат, сейчас очень популярно использование event storming. На личном опыте могу сказать, что только после знакомства с ним начал понимать суть ДДД и как должен вести себя агрегат с репозиторием.

Спасибо большое за отзыв и предложенное обсуждение.

  1. Полностью согласен с вами это идеальный вариант из книг. Но в своем проекте мы были готовы делать доменный слой правильным, для слоев выше мы разрешили себе делать отступления.

  2. В DDD комьюнити использование транзакций на уровне приложение применимо. Подробное описание можно найти в Implementing Domain-driven Design, Глава 12. Repositories, Managing Transactions или в Patterns, Principles, and Practices of Domain-Driven Design, Глава 20. Repositories, Transaction Management and Units of Work.

  3. Согласен, но каждый паттерн стоит применять по надобности, CQS, а тем более CQRS мне было бы очень тяжело продать бизнесу в рамках нашего проекта в виде стартапа.

  4. Доменные события очень объемная тема, но без них проект может существовать достаточно долго, поэтому я не включил их в статью и доклад. В книги 2002 года Эрика Эванса доменные события не упоминаются и появились только в Domain-Driven Design Reference начале 10-х.

Рад, что event storming вам так зашел.

Зарегистрируйтесь на Хабре, чтобы оставить комментарий