Как реализуете репозиторий (Doctrine, Analogue, ручками, etc)

Ничего себе у тебя бомбит. Это что-то личное?
Почему бомбит, я сразу же указал на проблему. Как и пару раз до этого.

При этом ты сам же тут же подтвердил мои слова, что это не лучший код.
Это какой-то недоделанный пример для какой-то презентации
 
А для чего же тогда используете ES-модели? Или имелось ввиду модели без ES-инфраструктуры, а в репозиториях получаем все события и в рамках транзакции пишем в БД, например, нативным SQL или датамэппером.
Если так, то получается красиво, используем доменную модель, соблюдаем SRP, можно любую глубину собрать по связям моделей, события выстраиваются в линию, и в персистентности у нас чистый оптимизированный SQL без оверхеда.
 
Doctrine 2.5 по мне более элегантный и функциональный нежели Analogue.
Несомненно. Код analogue проще понять именно потому что он небольшой. Он и не претендует на прям полноценный DM, это такая минималистичная реализация самых основных кейсов.

люди очень большое значение придают тому, как должно сохраняться
Скорее просто неохота вручную делать закат солнца. Хочется persist() и всё, а не фигурно выпиливать SQL лобзиком.
 
А для чего же тогда используете ES-модели? Или имелось ввиду модели без ES-инфраструктуры, а в репозиториях получаем все события и в рамках транзакции пишем в БД, например, нативным SQL или датамэппером.
Если так, то получается красиво, используем доменную модель, соблюдаем SRP, можно любую глубину собрать по связям моделей, события выстраиваются в линию, и в персистентности у нас чистый оптимизированный SQL без оверхеда.
Остаётся написать инструменты, которые будут это красиво и просто делать.
 
А для чего же тогда используете ES-модели? Или имелось ввиду модели без ES-инфраструктуры, а в репозиториях получаем все события и в рамках транзакции пишем в БД, например, нативным SQL или датамэппером.
Да, имелось в виду это.

Причин тут несколько.

Во-первых, именно модель знает о том, что же там внутри нее изменилось. Поэтому это логично записывать события внутри нее, а не снаружи. Это пока не требует именно ES-подхода, но очень близко к нему (мы просто записываем ->recordThat(new EventWasBuzzed() события по мере необходимости) .

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

В-третих, у нас была инфраструктурная проблема. Нужно было простое и понятное получение изменений модели. Дело в том, что если маппинг сложный и/или Doctrine по каким-то причинам не подходит для маппинга domain model напрямую, то получение диффа превращается в непростую задачу. Даже получив дифф (в виде массива свойств, которые изменились), требовались какие-то дополнительные проверки того, что именно привело к изменению, потому что в базе данные по разным причинам иногда хранятся по разному. Т.е. в модели может быть статус + какой-то флаг, а в базе это может хранится в виде одного числа. Повышался риск того, что реальные изменения в модели не будут соответствовать тем, что пойдут в базу. С явным же списком событий эта вероятность существенно снижается.

Есть ещё ряд некоторых неочевидных плюсов, но это основные.
 
Почему бомбит, я сразу же указал на проблему. Как и пару раз до этого.
А эти проблемы не имеют никакого значения, поскольку не имеют отношения к демонстрируемым концепциям. Там на это вообще не надо смотреть.
 
  • Like
Реакции: AmdY
Во-первых, именно модель знает о том, что же там внутри нее изменилось. Поэтому это логично записывать события внутри нее, а не снаружи. Это пока не требует именно ES-подхода, но очень близко к нему (мы просто записываем ->recordThat(new EventWasBuzzed() события по мере необходимости).
Получается в контексте TripPlanner при создании/обновлении/удалении нового маршрута нужно пробежать по всей глубине объектов (Route, Leg и т.д.) и собрать ивенеты со всех объектов, коллектора у нас нет?
 
Получается в контексте TripPlanner при создании/обновлении/удалении нового маршрута нужно пробежать по всей глубине объектов (Route, Leg и т.д.) и собрать ивенеты со всех объектов, коллектора у нас нет?
Тут лучше либо записывать события всегда в aggregate root, либо иметь какой-то EventHistory, инстанс которого передавать в дочерние объекты.

Всё равно чтобы добавить новый этап маршрута (Leg), тебе понадобится выполнять метод через Trip: $trip->enlargeRouteWithLocation($routeId, $date, $location), поэтому обычно первого варианта достаточно.
 
что в итоге приводит к функциональному программированию на промисах, которые пробрасываются 20 раз из объекта в объект, обрастая по пути все новыми обработчиками :)
я имею счастье такое дебажить
 
Зачем?
У тебя в роутере веб-запросов же нет пачки промисов. Не вижу принципиальной разницы.

Меня в таком подходе смущает другое - при событийном подходе получается довольно сложный flow control, и в какой-то момент уже фиг поймешь, кто на ком стоял. Разве что изолировать события в рамках одного небольшого контекста.
 
это немного шутка - в php нет асинхронных операций с промисами, которые непредсказуемо резолвятся, и все, действительно, можно задекорировать за Aggregate Root,
а если пойти дальше и развивать эту логику - получается ком событий, который обрастает обработчиками
 
Меня в таком подходе смущает другое - при событийном подходе получается довольно сложный flow control, и в какой-то момент уже фиг поймешь, кто на ком стоял. Разве что изолировать события в рамках одного небольшого контекста.
Это уже скорее проблема монолитных репозиториев и отсутствия bounded contexts, так что в плане изоляции ты прав.

Но без конкретных примеров тут что-либо говорить по существу сложно. Это можно так махать руками и говорить, что, например, ООП — это сложно, объект на объекте, объектом погоняет, получается какой-то непонятный ком объектов, который обрастает взаимосвязями и методами. Мы-то знаем, что на практике это просто обозначает, что человек не умеет в ООП, что у него скорее всего просто куча архитектурных проблем, которые в силу своей некомпетентности он не замечает и сваливает это всё на ООП.
 
Ту же мысль в голове держал, когда писал, но не стал уточнять. Поинт скорее в том, что с классами-интерфейсами-методами у нас есть IDE, а тут навигация опять ручками получается.

Щас пришла в голову другая мысль: у Кея ООП был в обмене сообщениями между объектами, и это все очень напоминает реализацию smalltalk style вызовов на java style language, не знаю, к чему я это даже :) Ну, конечно, в ST не так, я скорее про саму идею изначальную (объекты меняются сообщениями в соответствии с контрактами, и на этом всё).
 
В командо-событийной архитектуре есть свои концепции, упрощающие жизнь (saga, process manager), которые слушают события и отправляют команды. И, вероятно, если у нас непонятный ком из событий, то скорее всего мы не смогли просто разобраться в бизнес-логике и правильно выделить и описать процессы, происходящие между моделями.
 
Так понимаю ES-модель нарушает SRP, т.к. приходиться в рут аггрегате иметь инстанс накопителя событий и передавать его дочерним объектам, т.е. мы и за Entity отвечаем и знаем что есть коллектор событий.
 
ES-модель нарушает SRP, т.к. приходиться в рут аггрегате иметь инстанс накопителя событий и передавать его дочерним объектам, т.е. мы и за Entity отвечаем и знаем что есть коллектор событий.
Event и SRP описывают отношения объектов на разных уровнях, одно никак другому не мешает
 
Если это было бы автоматически сгенерировано, например, при использовании AOP, то нормально, но так сущность должна знать что у неё есть еще одна обязанность помимо бизнес-логики, это обработка Event, т.е. я не могу просто создать сущность и работать с ней, мне нужно внедрить это обработку.
 
Вот про AOP мне это кажется популярным заблуждением. :)
От того, что зависимость указана неявным образом, она все равно никуда не девается.
Но почему-то считается, что AOP - это верх архитектуры, а, сделать, скажем, трейт - это ататат.
 
сущность должна знать что у неё есть еще одна обязанность помимо бизнес-логики, это обработка Event, т.е. я не могу просто создать сущность и работать с ней, мне нужно внедрить это обработку.
Объект - это объединение данных и логики. Логика статична, а ее исполнение определяется событиями. Так объекты "реагируют" на внешние события.
Единственая сущность в природе, которая не реагирует на события - это черные дыры. Не надо их создавать :)
 
Последнее редактирование:
Так понимаю ES-модель нарушает SRP, т.к. приходиться в рут аггрегате иметь инстанс накопителя событий и передавать его дочерним объектам, т.е. мы и за Entity отвечаем и знаем что есть коллектор событий.
Здесь всё зависит от того, как ты определяешь «ответственность». Ответственность модели — моделировать понятие из предметной области (как ни странно). События, как часть этого процесса моделирования — лишь деталь реализации.

И забей на «передавать дочерним объектам», так обычно никто не делает, события записываются обычно только в aggregate root.

Выглядит это как-то так: https://github.com/qandidate-labs/b...ent-sourced-domain-with-tests/Invites.php#L44
 
Сверху