1

мне нужна помощь с чем-то я не могу получить мою голову обернутые вокруг относительно Repository и Услуги/Использование регистра модель (часть DDD дизайн) Я хочу реализовать в своем следующем проекте (Laravel PHP) ,Структура данных из хранилища для всех целей?

Все кажется ясным. Только одна часть DDD, которая запутывает, это структуры данных из репозиториев. Кажется, что люди выбирают структуры данных, которые должен вернуть репозиторий (массивы или сущности), но все это имеет недостатки. Один из них - это работа, в которой я смотрел свой опыт в прошлом. И один из них - у вас нет интерфейсов для простых структур данных (массива или простых атрибутов объекта).

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

Предыдущий опыт

В прошлом я создать сайт, который был API Centric с использованием рамок Kohana и Doctrine 2 ОРМ (данные модели преобразователя). Поток выглядел следующим образом:

Сайт контроллер → API клиент (HMVC вызовов) → контроллер API → Пользовательские Repository → Doctrine 2 ORM родной Repository/Entity-менеджер

Мой заказ Repository вернулся простые массивы, используя Doctrine2 DQL , Doctrine2 рекомендует данные результата массива для операций чтения. И да, это сделало мой сайт приятным и легким. Контроллер API просто преобразовал данные массива в JSON. Просто как тот.

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

Мой REST API поддерживается запросы, как
/api/users?include_latest_adverts=2&include_location=true
на ресурсе пользователей. Контроллер API передал include_location в репозиторий, который напрямую включал отношение местоположения. Контроллер прочитал latest_adverts=2 и вызвал репозиторий рекламы, чтобы получить последние 2 рекламы каждого пользователя. Массивы были возвращены.

Например, первый массив пользователя:

[ 
    name 
    avatar 
    adverts [ 
     advert 1 [ 
      name 
      price 
     ] 
     advert 2 [ 
      …. 
     ] 
    ] 
] 

Это оказалось очень успешным. Весь мой сайт использовал API. Было бы очень легко добавить нового клиента, потому что API был совершенно в производстве, уже используя oauth. Весь сайт работает на нем.

Но этот дизайн также имел недостатки. Мой контроллер по-прежнему содержал много логики для валидации, рассылки, параметров или фильтров, таких как has_adverts=true, чтобы получить пользователей только с объявлениями. Это означало бы, что если бы я создал новый порт, как новый новый интерфейс CLI, мне пришлось бы дублировать многие из этих контроллеров из-за всей проверки и т. Д. Но не дублирование, если бы я создал новый клиент. Таким образом, по крайней мере одна проблема была решена :-)

Мои панели администратора были полностью связаны с репозиторием/entity-менеджером doctrine2, чтобы ускорить разработку (вроде). Зачем? Поскольку у моего API были контроллеры жира с особыми функциональными возможностями только для веб-сайта (специальная проверка, отправка по почте для регистрации и т. Д.). Мне пришлось бы повторить работу или рефакторинг.Поэтому решили использовать объекты непосредственно, чтобы по-прежнему иметь четкий способ написания кода вместо того, чтобы переписывать все мои контроллеры API и переместить их в Службы (например, для сайта & admin). Время было проблемой при исправлении ошибок дизайна.

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

Нового проект (используя DDD идею) и дилемму со структурами данных

Хотя мне нравится идея будет API, ориентированными, я не хочу, чтобы мой следующий проект будет API, ориентированной в ядре, потому что я думаю, такая же функциональность должна быть доступна без протокола HTTP между ними. Я хочу создать ядро, используя идеи DDD.

Но мне понравилась идея с использованием слоя, который просто говорил как API и возвращает простые массивы. Идеальная база для любого нового порта, включая мой собственный интерфейс. Моя идея состоит в том, чтобы рассмотреть мои классы обслуживания как интерфейс API (вернуть данные массива), выполнить проверку и т. Д. Я мог бы иметь Службы специально для веб-сайта (регистрации) и простых служб, используемых администратором или фоновыми процессами. В некоторых случаях администрирования служба не требуется в любом случае для простого редактирования CRUD, я мог бы просто использовать репозитории напрямую. Контроллеры были бы очень тонкими. С этим созданием реального REST API просто возникнет вопрос о создании новых контроллеров с использованием тех же сервисов, которые выполняются моими интерфейсами контроллера.

Для внутренней логики, такой как бизнес-правила, было бы полезно иметь объекты (прозрачные интерфейсы) вместо массивов из репозиториев. Таким образом, я мог бы извлечь выгоду из определения некоторых методов, которые использовали некоторую логику на основе атрибутов. НО Если бы я использовал Doctrine2, и мои репозитории всегда возвращали Entities, мое приложение получило бы большой успех!

Одна структура данных обеспечивает производительность, но без четких интерфейсов, другая обеспечивает четкие интерфейсы, но плохую производительность при использовании шаблона Data Pattern, такого как Doctrine 2 (сейчас или в будущем). Также я мог бы привести к двум типам данных, которые были бы запутанными.

Я думал, что-то подобное этому потоку:

контроллер (тонкий) → UserService (. Включая проверки) → UserRepository (только для хранения) → красноречивый ОРМ

Почему Eloquent вместо Doctrine2? Потому что я хочу немного придерживаться того, что принято в рамках Laravel и сообщества. Поэтому я мог бы извлечь выгоду из модулей сторонних разработчиков, например, для создания интерфейсов администратора или аналогичных моделей на основе моделей (в обход моих правил DDD). Помимо использования сторонних модулей, я бы разработал свой основной материал, поэтому переключение всегда должно быть простым и не влиять на выбор структуры данных или производительность.

Eloquent - это шаблон activerecord. Поэтому у меня возникнет соблазн преобразовать эти данные в объекты POPO, такие как Doctrine2. Но нет ... как сказано выше, с доктринами2 реальных моделей сделает систему очень толстой. Поэтому я снова возвращаюсь к простым массивам. Знание этого будет работать как для любой другой реализации в будущем.

Но он чувствует себя плохо, всегда полагается на массивы. Особенно при создании внутренних бизнес-правил. Разработчику придется угадывать значения в массивах, не иметь автозаполнения в своей среде IDE, не может иметь специальных методов, например, в классах Entity. Но делать два способа борьбы с данными тоже плохо. Или я просто слишком совершенен;) Я хочу ОДИН ясную структуру данных для всех!

Интерфейсы здания и POPO будут означать много дублирования работы.Мне нужно было бы преобразовать модель Eloquent (только файл mapper, а не сущность) в объект объекта, реализующий этот интерфейс. Все это дополнительная работа. И в конечном итоге мой последний слой будет похож на API, таким образом, снова преобразуя его в массивы. Это тоже лишняя работа. Массивы снова кажутся сделкой.

Казалось, что так легко читать в DDD и Hexagonal. Кажется, так логично! Но на самом деле я борюсь с этой простой проблемой, пытаясь придерживаться принципов ООП. Я хочу использовать массивы, потому что это единственный способ быть на 100% уверенным, что я не зависим от выбора модели и запроса на выбор из моего ORM относительно производительности и т. Д. И не имею дублирования в преобразовании в массивы для представлений или API. Но нет четкого договора о том, как может выглядеть пользовательский массив. Я хочу ускорить свой проект, используя эти шаблоны, а не замедлить их :-) Так что не вариант иметь много конвертеров.

Теперь я прочитал много тем. Один делает интерфейсы POPO &, которые соответствуют нормальным объектам, таким как Doctrine2, могут вернуться, но со всей дополнительной работой для Eloquent. Переключение на Doctrine2 должно быть довольно простым, но это может повлиять на производительность настолько плохо или нужно будет преобразовать данные массива Doctrine2 в эти собственные интерфейсы сущностей. Другие предпочитают возвращать простые массивы.

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

Мы проектируем хранилища, чтобы изменить их? Не потому, что это «приятно» только по дизайну. Итак, как мы можем полагаться на полные сущности, если это оказывает такое большое влияние на производительность или дублирующую работу? Даже при использовании Doctrine2 только (в сочетании) эта же проблема возникла бы из-за ее производительности!

Все реализации ORM могли бы возвращать массивы, таким образом, не было бы дублирования работы. Хорошая производительность. Но мы пропускаем четкие контракты. И у нас нет интерфейсов для массивов или атрибутов класса (в качестве обходного пути) ... Ugh;)

Я просто пропустил недостающий блок на наших языках программирования? Интерфейсы на простых структурах данных?

Можно ли сделать все массивы и передовую бизнес-логику говорить с этими массивами? Таким образом, нет классов с четкими интерфейсами. Любые предварительно просчитанные данные (обычно возвращаемые методом Entity) будут находиться внутри ключа массива, определенного классом Service. если не мудро, какова альтернатива, учитывая все вышеперечисленное?

Я был бы очень признателен, если бы кто-то с большим опытом работы в этом «домене» с учетом производительности, различных реализаций ORM и т. Д. Мог рассказать мне, как он/она справился с этим?

Заранее благодарен!

ответ

0

Я думаю, что вы имеете дело с чем-то похожим, с которым я борюсь. Решение, которое я имею в виду работы лучше всего:

  1. Entities/Хранилища
    • Использование и огибают лиц всегда при выполнении операций записи (создание вещей, обновление вещей, удаление вещей, и сложные комбинации их).
    • Иногда вы можете использовать Entities при выполнении операций чтения (если вы предполагаете, чтение, возможно, потребуется использовать для Write вскоре после того, как ... т.е. -.> FindById вскоре последовали -> сохранить).
    • В любое время, когда вы работаете с объектом (будь то запись или чтение), Хранилища должны быть местом для перехода. Вы должны сказать новым разработчикам, что они могут сохраняться только в базе данных через Entities и Repository.
    • Объекты будут иметь свойства, которые представляют собой некоторый объект домена (много раз они представляют таблицу базы данных с полями таблицы, но не всегда). Они также будут содержать логику/правила домена с ними (т. Е. Проверку, вычисления), чтобы они не были анемичными. Вы можете дополнительно иметь некоторые службы домена, если вашим сущностям нужна помощь в взаимодействии с другими объектами (необходимо инициировать другие события), или вам просто нужно дополнительное место для обработки дополнительной логики домена (выполнять вызовы репозитория для проверки некоторых уникальных условий).
    • Ваши репозитории предназначены исключительно для работы с объектами. Репозитории могут принимать сущности и выполнять некоторую работу с ними. Или они могут принимать только некоторые параметры и делать чтение/выборку во всех сущностях.
    • Некоторые репозитории будут знать, как сохранить некоторые объекты домена, которые являются более сложными, чем другие. Возможно, Entity, у которого есть свойство, которое содержит список других объектов, которые должны быть сохранены вместе с основной сущностью (вы можете глубже погрузиться в изучение общности корней, если хотите).
    • Интерфейсы к репозиториям находятся в вашем доменном слое, но не в реальных реализациях этих репозиториев. Таким образом, у вас может быть версия Eloquent или что-то еще.
  2. Другие запросы (Таблица Data Gateway)
    • Эти запросы не будут работать с сущностями. Они просто будут принимать параметры и возвращать такие вещи, как массивы или POPO (простые старые объекты PHP).
    • Много раз вам нужно будет выполнить Чтения, которые не возвращаются красиво в единую Entity. Эти Чтения, как правило, больше предназначены для отчетов (не для операций с подобными CRUD, например, для чтения пользователя в форме редактирования, которая в конечном итоге отправляется и сохраняется). Например, у вас может быть отчет, состоящий из 200 строк данных JOINed. Если вы использовали Repositiory и пытались вернуть большие глубокие объекты (со всеми связями, заполненными или даже ленивыми), тогда у вас будут проблемы с производительностью. Вместо этого используйте шаблон Table Data Gatway. Вы просто показываете данные и не нуждаетесь в мощности ООП здесь. Однако выведенные данные могут содержать идентификаторы, которые через пользовательский интерфейс могут использоваться для инициирования вызовов методов сохранения хранилища.
    • Когда вы разрабатываете свое приложение, когда вы сталкиваетесь с необходимостью нового запроса чтения/отчета, создайте новый метод в каком-то классе где-нибудь в вашей папке Data Data Gatway. Вы можете обнаружить, что вы уже создали аналогичный запрос, поэтому посмотрите, как вы можете консолидировать другой запрос. При необходимости используйте некоторые параметры, чтобы сделать запросы метода шлюза более гибкими в определенных способах (например, столбцы для выбора, порядок сортировки, разбиение на страницы и т. Д.). Не делайте ваши запросы слишком гибкими, хотя, здесь возникают ошибки/ORM! Вам необходимо ограничить ваши запросы в определенной степени тем, где, если вам нужно их заменить (возможно, другой механизм базы данных), вы можете легко понять, что такое допустимые варианты и нет. Это зависит от вас, чтобы найти правильный баланс между гибкостью (так что у вас больше DRY-кода) и ограничений (так что вы можете оптимизировать/заменить запросы позже).
    • Вы можете создавать сервисы в своем Домене для обработки параметров приема, а затем передавать их в Шлюз данных таблицы, а затем получать обратно массивы, чтобы еще немного мутировать. Это сохранит вашу логику домена в домене (и вне уровня инфраструктуры/сохранения в хранилище данных & Table Data Gateway).
    • Опять же, как и в репозитории, используйте интерфейсы в своих службах домена, чтобы детали реализации не выходили из уровня вашего домена и находятся в фактической папке Data Data Gateway.
Смежные вопросы