Repository vs ActiveRecord
- BrusSENS
- Сообщения: 565
- Зарегистрирован: 2012.07.26, 06:51
- Откуда: Новороссийск
- Контактная информация:
Repository vs ActiveRecord
Всем привет! Решил начать небольшой холивар на тему того, что и как готовить.
Некоторое время назад я начал углубленно знакомиться с проектированием и начал потихоньку вникать в философию DDD, читая некоторые умные книги.
Итак, начнём.
AR - крутая штука, умеет многое, удобна, просто работать со связями. Но... Слишком жирные "модели", нарушает single responsibility, от большого количества связей раздувается до неимоверных размеров. В итоге, без опыта использования может попить много крови. Например, встречал, когда в User "модели" описывали все связи, которые есть в проекте, со всеми другими "моделями", жирнее некуда было.
Репозитории - удобная весчь. Позволяет управлять коллекцией, не перекладывая ответственности на сущности. Всё красиво, понятно и код вроде как выразительнее. Но... Пока делаете простые выборки (касаемо SQL) сущностей - всё круто и просто. Но только появляется некая ситуация, когда нужно Lazy и Eager, или нужно сделать JOIN и профильтровать поля - это просто превращается в поиск элегантного решения, которое очень сложно найти. Некоторые советуют "юзать прокси", насчёт этого я вообще промолчу.
Так вот хотелось бы от вас услышать ваше мнение по поводу решения подобных проблем при разработке, может кто уже имеет элегантные решения, ведь сама идея, лично мне очень нравится, но вот всё портит сложность реализации подобных гибких выборок, связей и фильтров.
Некоторое время назад я начал углубленно знакомиться с проектированием и начал потихоньку вникать в философию DDD, читая некоторые умные книги.
Итак, начнём.
AR - крутая штука, умеет многое, удобна, просто работать со связями. Но... Слишком жирные "модели", нарушает single responsibility, от большого количества связей раздувается до неимоверных размеров. В итоге, без опыта использования может попить много крови. Например, встречал, когда в User "модели" описывали все связи, которые есть в проекте, со всеми другими "моделями", жирнее некуда было.
Репозитории - удобная весчь. Позволяет управлять коллекцией, не перекладывая ответственности на сущности. Всё красиво, понятно и код вроде как выразительнее. Но... Пока делаете простые выборки (касаемо SQL) сущностей - всё круто и просто. Но только появляется некая ситуация, когда нужно Lazy и Eager, или нужно сделать JOIN и профильтровать поля - это просто превращается в поиск элегантного решения, которое очень сложно найти. Некоторые советуют "юзать прокси", насчёт этого я вообще промолчу.
Так вот хотелось бы от вас услышать ваше мнение по поводу решения подобных проблем при разработке, может кто уже имеет элегантные решения, ведь сама идея, лично мне очень нравится, но вот всё портит сложность реализации подобных гибких выборок, связей и фильтров.
Native Web - небольшой блог о веб разработке (временно на ремонте)
Режим обслуживания сайта для Yii 2.x.x
Режим обслуживания сайта для Yii 2.x.x
- samdark
- Администратор
- Сообщения: 9489
- Зарегистрирован: 2009.04.02, 13:46
- Откуда: Воронеж
- Контактная информация:
Re: Repository vs ActiveRecord
Модели слишком жирные только если вы сами их такими сделаете. Обычно они умеренно жирные SPR нарушает AR по определению. Он для этого и сделан и поэтому для многих задач удобен, а для некоторых фатально непригоден. Только связями катастрофически раздуть AR как-то не особо реально. Методы простейшие, назначение одно.
Да, репозитории писать бывает не просто и не быстро. Зато можно запилить оптимально и перепилить в одном месте, если что.
За гибкость приходится платить... за негибкость тоже
Да, репозитории писать бывает не просто и не быстро. Зато можно запилить оптимально и перепилить в одном месте, если что.
За гибкость приходится платить... за негибкость тоже
Нравится Yii? Давайте сделаем его лучше!.
- BrusSENS
- Сообщения: 565
- Зарегистрирован: 2012.07.26, 06:51
- Откуда: Новороссийск
- Контактная информация:
Re: Repository vs ActiveRecord
В том то и дело, что пока всё просто - всё хорошо. Опять же ясно, что серебряной пули не бывает.
Это да. Поэтому и хочется, что бы знающие люди поделились своим опытом, т.к. встречающиеся абстрактные решения ничего общего с реальностью не имеют. Спецификации? Бред, как по мне, удобства не добавляют, лучше какой-то абстрактный билдер критерии сделать. И пять таки вопрос в том, как правильнее сделать передачу JOIN фильтров по другим репозиториям. Я в соседней теме своё видение связей представлял, но ни одного ответа так и не получил.
Native Web - небольшой блог о веб разработке (временно на ремонте)
Режим обслуживания сайта для Yii 2.x.x
Режим обслуживания сайта для Yii 2.x.x
- BrusSENS
- Сообщения: 565
- Зарегистрирован: 2012.07.26, 06:51
- Откуда: Новороссийск
- Контактная информация:
Re: Repository vs ActiveRecord
Тут касательно AR могу сказать, что было бы не плохо объяснять знакомящимся с AR и Yii в целом, что из себя представляют связи и для чего они нужны.
Например есть User, UserProfile и Post. User должен внутри себя только по getProfile получать связь с профилем, а посты отбирать через Post::findByUserId($userId); вне самой модели. Тут SPR тоже часто нарушают, имхо. Не должен User знать о Post'ах, ни его это прерогатива.
P.S.: немного отошёл от темы.
Native Web - небольшой блог о веб разработке (временно на ремонте)
Режим обслуживания сайта для Yii 2.x.x
Режим обслуживания сайта для Yii 2.x.x
Re: Repository vs ActiveRecord
или не обязательно абстрактный и не обязательно билдер. Просто критерию. Можно под конкретный репозиторий написать, постепенно усложняя при необходимости. Я так сделал на текущем проекте.
непонятна проблема.
- BrusSENS
- Сообщения: 565
- Зарегистрирован: 2012.07.26, 06:51
- Откуда: Новороссийск
- Контактная информация:
Re: Repository vs ActiveRecord
Если не сложно, можете пример привести? Просто в моём понимании, хорошая критерия - это билдер, неважно текучий или нет. Посему хочется увидеть, как ещё можно подойти.
Например, есть у нас агрегат User, Order и Product. По логике User знать о Order и Product не должен. Но нам нужно вывести пользователей, которые фильтруются по некой таблице из агрегата Order, например, пользователей, заказавших некоторый Product. AR на позволяет юзать joinWith, вроде как, а вот что делать в случае, когда у нас получение всех сущностей происходит через репозиторий? Надеюсь понятно объяснил.
Native Web - небольшой блог о веб разработке (временно на ремонте)
Режим обслуживания сайта для Yii 2.x.x
Режим обслуживания сайта для Yii 2.x.x
Re: Repository vs ActiveRecord
ну билдер - это реализация заполнения атрибутов объекта. не в этом же соль.
у меня go.
что то типа такого:
Код: Выделить всё
$phoneCriteria = (new PhoneCriteria)
->field('session_id', $sessionId)
->sort('id', 'desc');
$phoneRepo->findByCriteria($phoneCriteria);
не надо смешивать понятия агрегат и таблицы.BrusSENS писал(а): ↑2017.09.04, 16:09Например, есть у нас агрегат User, Order и Product. По логике User знать о Order и Product не должен. Но нам нужно вывести пользователей, которые фильтруются по некой таблице из агрегата Order, например, пользователей, заказавших некоторый Product. AR на позволяет юзать joinWith, вроде как, а вот что делать в случае, когда у нас получение всех сущностей происходит через репозиторий? Надеюсь понятно объяснил.
надо заджойнить - заджойните на мощностях вашей ORM, не надо в данном контексте упоминать другие агрегаты и репозитории. Т.е. ничего пробрасывать не надо.
- BrusSENS
- Сообщения: 565
- Зарегистрирован: 2012.07.26, 06:51
- Откуда: Новороссийск
- Контактная информация:
Re: Repository vs ActiveRecord
Ну примерно такой вариант я и реализовал:zelenin писал(а): ↑2017.09.04, 16:18 ну билдер - это реализация заполнения атрибутов объекта. не в этом же соль.
у меня go.
что то типа такого:Код: Выделить всё
$phoneCriteria = (new PhoneCriteria) ->field('session_id', $sessionId) ->sort('id', 'desc'); $phoneRepo->findByCriteria($phoneCriteria);
Код: Выделить всё
$criteria = (new UserCriteria)
->equals('fieldId', $val)
->like('fieldId', $val)
Это то понятно, что таблицы у нас тут не при чём. Но всё таки нужно быть реалистами. Репозитории работающие с РСУБД в качестве хранилища будут отличаться от репозиториев для отличных от РСУБД хранилищ.
Native Web - небольшой блог о веб разработке (временно на ремонте)
Режим обслуживания сайта для Yii 2.x.x
Режим обслуживания сайта для Yii 2.x.x
Re: Repository vs ActiveRecord
я реалист и практик, но не понимаю о чем вы. Возможно вам кажется очевидным какие-то моменты, но вы лучше их поясняйте.
У меня например есть под рукой два приложения - на postgres и на mongo. Конечно они ВНУТРИ отличаются - ведь используются разные либы для доступа, но меня мало интересует что там внутри, я ведь репозитории создавал, чтобы знать, что получу наружу.
Поясняйте.
- BrusSENS
- Сообщения: 565
- Зарегистрирован: 2012.07.26, 06:51
- Откуда: Новороссийск
- Контактная информация:
Re: Repository vs ActiveRecord
И вот появился вопрос, например, нужно выбрать заказы пользователя, я принципиально считаю, что сущности заказов не должны быть вложены в сущность пользователя, поэтому какая реализация подойдёт больше?
1. Выбираем заказы, передав в качестве аргумента OrderRepository->getAllByUser() ID или всю сущность?:
Склоняюсь ко 2 варианту из-за возможного различия типа ID (int/string)
2. Выбираем все заказы всех пользователей, и передаём их как VO или по отдельности:
Опять же склоняюсь ко второму варианту, т.к. по идее это у нас получается некая коллекция.
1. Выбираем заказы, передав в качестве аргумента OrderRepository->getAllByUser() ID или всю сущность?:
Код: Выделить всё
$user = $userRepo->gelById(1);
$orders = $orderRepo->getAllByUserId($user->getId());
// Или
$users = $userRepo->getById(1);
$orders = $orderRepo->getAllByUser($user);
$view->render(
'user' => $user,
'orders' => $orders
]);
2. Выбираем все заказы всех пользователей, и передаём их как VO или по отдельности:
Код: Выделить всё
$users = $userRepo->getAll();
$orders = $orderRepo->getAllByUsers(Array::arrayFromPropertyValues($users, 'id'));
$view->render(
'user' => $user,
'orders' => $orders
]);
// или
$users = $userRepo->getAll();
$orders = $orderRepo->getAllByUsers(Array::arrayFromPropertyValues($users, 'id'));
$collection = new UserWithOrdersCollection($users, $orders);
$view->render(
'collection' => $collection
]);
Native Web - небольшой блог о веб разработке (временно на ремонте)
Режим обслуживания сайта для Yii 2.x.x
Режим обслуживания сайта для Yii 2.x.x
- samdark
- Администратор
- Сообщения: 9489
- Зарегистрирован: 2009.04.02, 13:46
- Откуда: Воронеж
- Контактная информация:
Re: Repository vs ActiveRecord
А чего не getUserWithOrders()?
Нравится Yii? Давайте сделаем его лучше!.
- BrusSENS
- Сообщения: 565
- Зарегистрирован: 2012.07.26, 06:51
- Откуда: Новороссийск
- Контактная информация:
Re: Repository vs ActiveRecord
Ну я же говорю: есть у нас заказы, и есть у нас пользователи. Мне нужно выбрать пользователей, купивших тот или иной продукт. Сделать это проще всего через JOIN, если это касается РСУБД. Но есть у меня требование того, что пользователи и магазин - это два совершенно разных и как можно более независимых модуля. Я хочу иметь возможность более безболезненно отключить модуль магазина. Тогда что мне делать с JOIN'ом, жёстко прописанным в репозитории? Тут адаптеры мне на ум и приходят. Появляется хоть какая то надежда на независимость.zelenin писал(а): ↑2017.09.04, 16:48 я реалист и практик, но не понимаю о чем вы. Возможно вам кажется очевидным какие-то моменты, но вы лучше их поясняйте.
У меня например есть под рукой два приложения - на postgres и на mongo. Конечно они ВНУТРИ отличаются - ведь используются разные либы для доступа, но меня мало интересует что там внутри, я ведь репозитории создавал, чтобы знать, что получу наружу.
Поясняйте.
Native Web - небольшой блог о веб разработке (временно на ремонте)
Режим обслуживания сайта для Yii 2.x.x
Режим обслуживания сайта для Yii 2.x.x
- BrusSENS
- Сообщения: 565
- Зарегистрирован: 2012.07.26, 06:51
- Откуда: Новороссийск
- Контактная информация:
Re: Repository vs ActiveRecord
Что если Shop и User два отдельных модуля? При отключении Shop, в UserRepository появится метод, который просто не нужен.
Upd: Или мы сменили хранилище ShopRepository на файлы, например?
Последний раз редактировалось BrusSENS 2017.09.04, 17:09, всего редактировалось 1 раз.
Native Web - небольшой блог о веб разработке (временно на ремонте)
Режим обслуживания сайта для Yii 2.x.x
Режим обслуживания сайта для Yii 2.x.x
Re: Repository vs ActiveRecord
ну это вообще не по теме. Тут нет repo vs AR, тут нет какой-либо проблемы с репо. Тут просто вопросы о вкусовщине. Как хотите так и делайте.BrusSENS писал(а): ↑2017.09.04, 17:00 И вот появился вопрос, например, нужно выбрать заказы пользователя, я принципиально считаю, что сущности заказов не должны быть вложены в сущность пользователя, поэтому какая реализация подойдёт больше?
1. Выбираем заказы, передав в качестве аргумента OrderRepository->getAllByUser() ID или всю сущность?:Склоняюсь ко 2 варианту из-за возможного различия типа ID (int/string)Код: Выделить всё
$user = $userRepo->gelById(1); $orders = $orderRepo->getAllByUserId($user->getId()); // Или $users = $userRepo->getById(1); $orders = $orderRepo->getAllByUser($user); $view->render( 'user' => $user, 'orders' => $orders ]);
2. Выбираем все заказы всех пользователей, и передаём их как VO или по отдельности:Опять же склоняюсь ко второму варианту, т.к. по идее это у нас получается некая коллекция.Код: Выделить всё
$users = $userRepo->getAll(); $orders = $orderRepo->getAllByUsers(Array::arrayFromPropertyValues($users, 'id')); $view->render( 'user' => $user, 'orders' => $orders ]); // или $users = $userRepo->getAll(); $orders = $orderRepo->getAllByUsers(Array::arrayFromPropertyValues($users, 'id')); $collection = new UserWithOrdersCollection($users, $orders); $view->render( 'collection' => $collection ]);
- BrusSENS
- Сообщения: 565
- Зарегистрирован: 2012.07.26, 06:51
- Откуда: Новороссийск
- Контактная информация:
Re: Repository vs ActiveRecord
Ага, понял.
А вообще хотелось бы что бы опытные девелоперы рассказали, на какие камни например натыкались, используя AR и Repository. Преимущества обоих паттернов понятны. Но вот сложности в реализации присутствуют по любому, вот и хотелось бы услышать, какие это сложности и как их решали.
Native Web - небольшой блог о веб разработке (временно на ремонте)
Режим обслуживания сайта для Yii 2.x.x
Режим обслуживания сайта для Yii 2.x.x
Re: Repository vs ActiveRecord
ок, хороший вопрос. Но у нас модуль продуктов знает, что есть юзеры. То есть как минимум они должны присутствовать в модуле продуктов. И общаться с модулем юзеров через адаптеры.BrusSENS писал(а): ↑2017.09.04, 17:05 Ну я же говорю: есть у нас заказы, и есть у нас пользователи. Мне нужно выбрать пользователей, купивших тот или иной продукт. Сделать это проще всего через JOIN, если это касается РСУБД. Но есть у меня требование того, что пользователи и магазин - это два совершенно разных и как можно более независимых модуля.
Соответственно ProductRepository имеет метод getUsersByProduct(), возвращающий User'ов модуля Product, через UsersByProductProviderInterface, реализованный для модуля User. Эта реализация будет знать о модуле User.
Можно и проще обойтись - у нас реализация ProductRepository будет не только основана на некоей ORM, но и на конкретном модуле User. Но это бОльшая связанность.
да, правильно приходят. Через адаптеры мы модули и связываем.
Re: Repository vs ActiveRecord
Разделите на Domain Model и Read Model:
viewtopic.php?f=34&t=42014&p=207524#p207524
Прокси достаточно удобны:
viewtopic.php?f=34&t=43009
- BrusSENS
- Сообщения: 565
- Зарегистрирован: 2012.07.26, 06:51
- Откуда: Новороссийск
- Контактная информация:
Re: Repository vs ActiveRecord
Думал насчёт этого. Получается, что у насElisDN писал(а): ↑2017.09.04, 17:18 Разделите на Domain Model и Read Model:
viewtopic.php?f=34&t=42014&p=207524#p207524
то появятся ещё и
репозиториев, подмена которых станет, скорее всего, неприятным делом.
Да, читал Ваши статьи, но прокси оттолкнул сразу. Ну не понравилось, как реализовано, неявно что ли... Не знаю даже, как описАть.
Native Web - небольшой блог о веб разработке (временно на ремонте)
Режим обслуживания сайта для Yii 2.x.x
Режим обслуживания сайта для Yii 2.x.x
Re: Repository vs ActiveRecord
так lazy это и есть неявная ленивая подгрузка.BrusSENS писал(а): ↑2017.09.04, 17:34Думал насчёт этого. Получается, что у насElisDN писал(а): ↑2017.09.04, 17:18 Разделите на Domain Model и Read Model:
viewtopic.php?f=34&t=42014&p=207524#p207524то появятся ещё ирепозиториев, подмена которых станет, скорее всего, неприятным делом.
Да, читал Ваши статьи, но прокси оттолкнул сразу. Ну не понравилось, как реализовано, неявно что ли... Не знаю даже, как описАть.
- BrusSENS
- Сообщения: 565
- Зарегистрирован: 2012.07.26, 06:51
- Откуда: Новороссийск
- Контактная информация:
Re: Repository vs ActiveRecord
Это понятно. Я про неявность самой реализации. В общем не понравилась реализация с прокси, хотя ничего пока стоящего, чем заменить в голову не приходит.
Native Web - небольшой блог о веб разработке (временно на ремонте)
Режим обслуживания сайта для Yii 2.x.x
Режим обслуживания сайта для Yii 2.x.x