Pull to refresh

Comments 39

Отличная причина создать свой фреймворк, например Maravel )
Давно известно что программист с Тейлора посредственный и он любит велосипеды посредственного качества :D

Чего стоит только противоракетный маневр с местоположением моделей...

Это про перемещение моделей в папку Models?

Следите за руками (официальная документация):
4.2 — Models typically live in the app/models directory
5.0 — Models typically live in the app directory
8.0 — Models typically live in the app\Models directory.
Загадка от Жака Фреско.

Нахрена?

На размышление даётся 30 секунд.
В 4.2 все модели начали создаваться в app/models, и все их туда пачками ложили, но это не совсем правильно, поэтому в 5.0 сказали — ложите их куда хотите, а если вы сами себе «злобные буратины» вот вам дефолт «app», чтобы вы мучились. Ну и наконец начали как и контролеры, сервисы и всё остальное держать сгруппированными. Но глупого народа много, народ так и продолжал держать всё в корне «app», потому в 8.0 и сделали отдельную папку для таких вот буратин, но никто не запрещает и более того даже нужно, ложить модели туда, где они должны по логике проекта лежать.
Повеяло симфонией с её Controller и AbstractController (как то так) при переходе с 4 на 5.

Для меня этот фрейм умер на 4.2 а для всей команды на 5.* и за постоянных внутренних переделок фреймворка. Симфония будет лучше с цайклс вполне съедобно, если не нравится доктрина как мне.


Сам сижу на yii2 и на nodejs, это позволяет быстрей пробовать прототипы для бизнеса.


Текущий подход yii3 очень нравится, ребята двигаются в верном направлении:
1 симфони консольные команды легкие и элегантные.
2 легкие веб контролеры с di, мы используем то что нам нужно.


Насчет статьи, код отформатирован через phpcs под кодстайл фреймворка, считаю что стандартное форматирования phpcs2 лучшие, так как соответствует пхпшторму.


Спасибо за статью и опыт.

Пару лет работал с Symfony, мне кажется производительность труда (программиста) все-таки выше в Laravel, некоторые вещи слишком усложнены искусственно в Symfony. Одно сохранение модели чего стоит
Сохранение модели к симфони не имеет отношения. Не нравится доктрина — используйте другую ORM.
UFO just landed and posted this here
Вот из официальной доки:

// you can fetch the EntityManager via $this->getDoctrine()
// or you can add an argument to the action: createProduct(EntityManagerInterface $entityManager)
$entityManager = $this->getDoctrine()->getManager();

$product = new Product();
$product->setName('Keyboard');
$product->setPrice(1999);
$product->setDescription('Ergonomic and stylish!');

// tell Doctrine you want to (eventually) save the Product (no queries yet)
$entityManager->persist($product);

// actually executes the queries (i.e. the INSERT query)
$entityManager->flush();
UFO just landed and posted this here
Вопрос принципиальный
Если придерживаться мнения, что разработка — должна происходить быстро и доставлять удовольствие программисту, то тут — перебор. Программист целых 3 строки будет миллион раз повторять в коде, чтобы сохранить запись. Не говоря уже о читаемости — «persist» переводится как «сохранить», но оно не сохраняет. «flush» переводится как «сбросить», «очистить», но оно сохраняет в базу.
Но это, конечно, holy war. Кому-то нравится программировать, кому-то нравится смотреть на абстракции в коде.

Ну, наименования тут взяты прямиком из Java Persistence Api (JPA), лично мне они тоже кажутся несколько неудачными — я-то привык к Add и SaveChanges :-)


Что же до числа строчек — то тут всё просто. От первой строчки вы не избавитесь никак, соединение с БД по-любому нужно или получить, или создать. А разделение persist/flush нужно чтобы была возможность сохранять в БД несколько сущностей за раз.

От первой строчки вы не избавитесь никак, соединение с БД по-любому нужно или получить, или создать.

В Ларавеле не так, блин… $product = new Product(); $product->save(); само достанет из кишок фреймворка дефолтное соединение или откроет его, если ещё не открыто...

UFO just landed and posted this here
Этим мне и нравится доктрина: eventually save, а не сразу, в отличие от многих AR.
дело вкуса :) мне просто не хочется каждый раз повторять одни и те же строки. я пишу код, чтобы делать жизнь юзеров лучше, а не чтобы наслаждаться идеальностью абстракций в своем коде

Судя по этому комментарию — вы не работали с доктриной, иначе бы не писали подобного. Ёлка удобнее доктрины только для чтения и только для относительно простых вещей. А работа с ней на запись — это сущий ад, особенно, когда дело касается нормальной транзакционности и отношений.


Вы же понимаете, что в доктрине в идеальном случае достаточно вызывать один раз persist($object) для просчёта отношений + flush() для сохранения состояния и всё сохранится в БД:
1) В одной транзакции (если включено)
2) Исключая дубликаты
3) В нужном порядке
4) Только те данные, что реально изменились
5) Включая все отношения этого объекта, которые были изменены (даже какие-нибудь many2many).


Например
$user = new User();
// В eloquent пришлось бы тут делать save, что б появился PK у модели.

$user->comments = $user->comments->filter(fn ($c) => $c->id === 42);
// eloquent: $user->comments()->detach($user->comments()->first(42));

$user->comments[] = new Comment();
// eloquent: $user->comments()->attach(new Comment());

$user->friends[] = new User();
// eloquent: $user->friends()->associate(new User());

/// ... etc

$em->persist($user);
$em->flush();
// eloquent: $user->save()

В eloquent подобные операции — смерти подобны. А потом это ещё заворачивать в транзакцию…

Запускаем какое-то атомарное действие, которое задействует несколько сервисов. В вашем случае при ошибке в середине или в конце могут остаться хвосты в базе и данные могут стать несогласованными, кроме того, разные сервисы могут работать с разными объектами, которые будут представлять одну и ту же строку в БД. Широкие возможности для выстрела в ногу. И вряд ли это улучшит жизнь обслуживающих код и всех клиентов. В случае с UoW+IdentityMap сохранение будет только там, где вы явно коммитите изменения в БД, когда все этапы работы с представлениями объектов из строк БД уже пройдены.

я пишу код, чтобы делать жизнь юзеров лучше, а не чтобы наслаждаться идеальностью абстракций в своем коде
А паттерны (включая тот же UoW, IM) от сырости или оттого, что коту нечего делать, завелись, видимо?

ORM это всегда оверхэд по производительности, по коду и по логике. То что на SQL делается за 1 логическую операцию, на ORM обрастает абстракцией, которую очень тяжело контролировать. Сегодня борол Laravel: нормализовали клиентов, появился detail к клиентам с аккаунтами. В одном из режимов надо показывать всех клиентов, кроме тех, которые есть только в одном определенном аккаунте. Клиентов пара миллионов. Laravel для педжинейшена делает 2 запроса к БД: один на COUNT(*), один уже на данные с ORDER BY и LIMIT. Оптимизируя один из запросов, второй начинает недопустимо проседать. В ход шли самые современные методы MySQL: WITH, хинты. В общем, на ровном месте, борьба с ветряными абстракциями на несколько часов, которая разрешилась только практически pure sql

Если вас сильно напрягают отдельные persist и flush, то можно создать сервис, объединяющий эти действия.

$product = new Product();
$entityPersister->save($product);
UFO just landed and posted this here

Ну я знаю как минимум 3 случая ещё, когда feature PR отклонялся, а потом дядя Ти выкатывал какой-то лютый **** со словами "смотрите, какую я фичу запилил". Так что ничего удивительного. Вы не первый — вы не последний.

То, что идею себе присвоил — не так обидно, как то, что он такой плохой код добавил :)
Вообще Laravel довольно неоднозначный фреймворк. На первый взгляд он очень функционален и в нем реализовано много полезных штук, но как только приходится решать нетривиальную задачу с помощью этих самых штук — начинаешь вспоминать разработчиков матерным словом и переделывать их работу. То же самое касается производительности — очень многое реализовано крайне неэффективно и начинает дико тормозить с ростом посещаемости.
UFO just landed and posted this here
Пожалуй самый главный тормоз это модели, а точнее доступ к атрибутам. Они реализованы в корне неверно, и вот я посмотрел в 8 версии ларавела — все то же самое. А проблема вот в чем: модель внутри хранит сырые данные из базы, и при каждом обращении к атрибуту вызываются касты и мутаторы, и это никак даже не кэшируется. Соотвественно запись в атрибут сразу конвертирует значение в понятное базе. А должно быть наоборот — конвертация один раз при чтении или записи в базу.
В нашем проекте есть json поля в базе, и много бизнес логики для них, соответственно обращение к таким атрибутам очень частое, и вот при каждом обращении под капотом вызывается json_decode/json_encode. Я был разочарован когда раскопал откуда тормоза пошли.

Второй пример это функция Arr::get(), а точнее ее использование. Она позволяет получить значение из вложенного массива передавая путь вида «path.to.value», и соответственно реализация содержит explode() и цикл по сегментам пути. Так вот очень важная функция config() под капотом вызывает ту самую Arr::get() при каждом обращении, никак не кэшируя результат. И если у вас где-то в большом цикле вызов config() — прощай производительность. Эта Arr::get() используется и некоторых в других местах аналогичным способом.

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

Когда я обнаружил проблему с моделями (профайлером), исправление ускорило код примерно на 30%. Пришлось сделать самодельный кэш атрибутов и использовать в нагруженных местах.

UFO just landed and posted this here
Тейлор классно умеет продвигать. Любыми способами)
и у него получается. Пипл хавает.
Пиплов так много набралось, что совместными усилиями все таки смогли сделать приличный феймворк, хоть и с достаточным количеством оверинженеринга
Сам буквально пару недель назад попал в такую же ситуацию, расшарил в ишьюсах свое виденье АПИ для DB::afterCommit хуков, получил в ответ: «мы не будем пока это реализовывать». Через 2 дня такая же реализация с небольшм переименованием была влита в мастер
Тайлер быстро говнокодит фичу, потом приходит community и спустя пару версий делает код более качественным. Нормальный процесс, зато на McLaren накопил выступлениями.

В целом было бы чхать на это, если бы он на некоторые больные места не накладывал свое вето, как например composite primary keys.
Sign up to leave a comment.

Articles