Pull to refresh

Comments 24

Хорошая статья для новичков и для введения в DDD. Конечно печалит наличие метода Update у репозитория. Представляет ли автор как будет выглядеть реализация этого метода, когда у агрегата будет допустим пять связанных сущностей или коллекций, а у этих коллекций будут свои связанные сущности?

А как апдейтить такие сущности?

Это именно тот вопрос, который очень старательно обходят стороной подобные статьи. Ведь если автор возьмет не банальную сущность заказ, а нечто действительно сложное (а зачем нам иначе DDD?) то код какого нибудь Update написанный руками отпугнет всякого.

Отвечая на ваш вопрос - в GO никак, инструменты которые позволяют сохранять графы объектов не взлетают, потому что никому особо не нужны тк в микросервисах DDD не часто нужен.

А как бы вы апдейтили не в голанге? Допустим у вас есть тот самый агрегат с пятью связанными сущностями и ваш текущий стек. Я наверное не очень понимаю проблему и чем подход в go отличался бы от подходов в других ЯП.

Не на go есть некоторый инструмент (hybernate, entity fw, doctrine) достаточно умный чтобы следить за каждым узлом в графе сущностей (тн агрегат) и при его изменении/удалении/появление нового узла переносить эти изменения в базу данных.

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

Один из способов не завязывать сущность на сущность. Потому что часто такие связи не являются оптимальными. Например если у вас постоялец в таверне у которого более 1000 заказов. Будет ли это значит что customer.orders содержит 1000 заказов? Оптимально ли загружать 1000 заказов в таком случае если мы просто хотим добавить ещё один? Можно тогда загружать последние 10 заказов, звучит более оптимальнее, но тогда это customer.latestOrders? Тогда зачем нам orders? И вообще что если я хочу поздравить кастомера с 1000 заказом, опять загружать все заказы чтобы посчитать?

Много вопросов мало ответов, выглядит красиво когда можно дёрнуть customer.orders, объектно ориентированно, но абсолютно продакшен не пригодно. Скорее всего вы заведёте репозиторий и сервис к нему, но уже получается сильно больше кода, красивой статьи не выйдет. Мне нравится идея наличия связей, когда customer.orders на самом деле будет прокси(со связью по id) репозиторием customer.orders.getLatest()/getAll() как eloquent в laravel. Но тогда придётся писать ещё больше кода.

Нужен или не нужен зависит от контекста и конкретной задачи. А инструменты есть. Из адекватных есть facebook/ent отлично справляется с сохранением графа объектов.

Собственно выше написал почему с ent не построить хорошую доменную модель.

DDD хорош при построении монолитов, но не для микросервисов и go (если конечно вы не решили строить монолит на go).

Так говорите, как будто монолит это плохо

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

Я скорее против того, чтобы делать монолиты на go, для этого лучше подойдет php, java или c#

А можно аргументы? Почему DDD плох для микросервисов?

Потому, что микросервисы предполагают, что в конкретном сервисе только один домен

тоже интересно почитать, учитывая что DDD - это вообще про архитектуру, еще на первых страницах Эванса сказано напрямую, что DDD это не про монолит vs soa. Поинт выше, что на го неудобно писать DDD, потому что подходящего фреймворка нет - как бы и clean architecture, и ddd призывают не привязываться к фреймворкам и отделять имплементацию от бизнес логики...

Пилить DDD на языке на котором нет обобщений, наверное, то еще удовольствие.

Обобщения/дженерики, если объективно, нужны в общем случае и чаще всего для базовых коллекций и алгоритмов. Например: списки, деревья, сортировка, поиск и т.д. И их отсутствие вовсе не ограничение для использования DDD или других концепций. Да и без DDD так называемая бизнес-логика чаще всего основана на конкретном описании, а не на обобщении.

Ну да, ну да, как же вы будете реализовывать Event-Sourucing(годная добавка к ДДД) без обобщений. Возьмем например такую реализацию , мне интересно как возможно реализовать AggregateBase<T> или DomainEvent<T: TIn> без обобщений? Через тип Any или Object? Это же печально.

И их отсутствие вовсе не ограничение для использования DDD или других концепций.

По мне так это ограничение. Но согласитесь это же не хилый костыль, например у меня есть PaymentDomain<T : IPaymentMethod>, и как мне реализовать плату через paypal, bank? Это возможно сделать даже на Perl, но какой ценой. А с обобщениями, тем более без type erasure это просто, красиво и комфортно.

Если у вас тип Т то используйте any, да, к сожалению добавится каст. Но в большинстве случаев тип Т имплементирует интерфейс и PaymentDomain<T : IPaymentMethod> лишь сахар для PaymentDomain(method IPaymentMethod)

Дженерики конечно добавят удобства для примитивов, но в остальном, интерфейсов в большинстве(99%) случаев достаточно

Очередная статья про DDD, которая посыпется, если сделать практическое применение изложенной программной архитектуры.

Если мне нужно получить список из 10 клиентов в городе N с наибольшим количеством отменённых заказов в этом городе. Это будет новый агрегат и новый репозиторий? И сколько у нас будет такого леса из агрегатов в мало-мальски сложном приложении? И самое главное - а что, если один и тот же частный агрегат кто-то решит использовать в двух кейсах, которые вот прямо сейчас похожи, а позже в них появятся различия.

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

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

Поэтому получение списка 10 клиентов в городе N с наибольшим количеством отменённых заказов в этом городе я бы делал через поисковой движок без применения агрегатов.

Only those users with full accounts are able to leave comments. Log in, please.