За последние 24 часа нас посетили 16917 программистов и 1632 робота. Сейчас ищет 651 программист ...

Хорошие практики Laravel

Тема в разделе "Laravel", создана пользователем Alexey Mezenin, 7 ноя 2017.

  1. Alexey Mezenin

    Alexey Mezenin Новичок

    С нами с:
    27 апр 2016
    Сообщения:
    17
    Симпатии:
    2
    Создал список хороших практик Laravel. Если у кого-нибудь есть чем дополнить, пожалуйста делитесь мыслями.

    Еще написал статью на эту же тему - Хорошие практики Laravel, принцип единственной ответственности (single responsibility principle), которая точно будет пролезна новичкам, мидлам и некоторым сениорам.
     
    alexforce2 нравится это.
  2. romach

    romach Старожил

    С нами с:
    26 окт 2013
    Сообщения:
    2.904
    Симпатии:
    719
    Вы таки большой молодец )

    p.s. давненько я не заходил на laravel.ru, сколько всего нового то.
     
    Alexey Mezenin нравится это.
  3. mkramer

    mkramer Суперстар
    Команда форума Модератор

    С нами с:
    20 июн 2012
    Сообщения:
    8.579
    Симпатии:
    1.760
    Хм. Странно читать совет использовать чаще Active Record. Считается же что это антипаттерн (хотя, в мелких приложениях и удобно)
     
  4. artoodetoo

    artoodetoo Суперстар
    Команда форума Модератор

    С нами с:
    11 июн 2010
    Сообщения:
    11.106
    Симпатии:
    1.243
    Адрес:
    там-сям
    Не понравилось, что автор намеренно составил корявый SQL запрос, чтобы противопоставить его няшному eloquent. Такая нарочитость ставит под сомнение ценность всего "сборника". Если вы не можете сформулировать запрос иначе как через двойной where exists, и всегда пишете "SELECT *", то anemic aсtive record только усугубит ваши проблемы.

    Важно сказать где и почему нежелательно использовать сырой SQL.
     
  5. Alexey Mezenin

    Alexey Mezenin Новичок

    С нами с:
    27 апр 2016
    Сообщения:
    17
    Симпатии:
    2
    Речь идет об ОРМ против сырого SQL. Можно Doctrine использовать, но это тоже плохо, т.к. это нестандартный инструмент для фреймворка.

    Этот SQL запрос составлен фреймворком. Это тот SQL, который генерирует Eloquent для кода из примера, который идет дальше. Выбрал запрос средней сложности, чтобы показать читаемость Eloquent запросов ("Почти как чистый английский"). Не показывать же разницу на User::all()

    Мое мнение такое, что сырой SQL нужно использовать в виде вставок DB::raw только там, где средставми ОРМ нельзя решить задачу. Да и тогда, в большинстве случаев, можно решить задачу без этих вставок.

    Ну и сырой SQL хорош там, где скорость выполнения запроса стоит на первом месте, перед удобством, стоимостью разработки и поддержки проекта и т.д.
     
  6. artoodetoo

    artoodetoo Суперстар
    Команда форума Модератор

    С нами с:
    11 июн 2010
    Сообщения:
    11.106
    Симпатии:
    1.243
    Адрес:
    там-сям
    Всё проще: желательно прятать детали реализации в "чёрный ящик" и разделять сферы ответственности. Поэтому SQL в контроллере нежелателен. Но он вполне допустим где-то в модели. (здесь "Модель" это не наследник класса Model, а более широкое понятие — то место, которое мы используем для получения и обновления данных. Модель прячет от нас детали обращения к БД/кешу/стороннему сервису.)

    С точки зрения разделения сфер ответственности, нет никакой, СОВСЕМ НИКАКОЙ разницы, напишете ли вы SQL-запрос или цепочку методов active record. Это явное указание как и откуда вы гребёте данные. Просто другой синтаксис. Поэтому когда вы разговариваете с адептами чистого кода, вас постоянно тыкают носом в антипаттерн active record.

    Чтобы спрятать запросы, используют не затычки active record, а абстракции более высокого уровня — репозитории. См. видео от Taylor Otwell. В любом случае, где-то внутри реализации у вас будет "низкий уровень абстракции". Вы просто задвигаете его подальше, чтобы сосредоточиться на бизнес задаче.

    Don’t call Eloquent models directly, Use Repositories!
    http://www.laravelbestpractices.com/

    ого. а я думал, что SQL это почти чистый английский, век живи, как говорится…

    SQL was initially developed at IBM by Donald D. Chamberlin and Raymond F. Boyce in the early 1970s. This version, initially called SEQUEL (Structured English Query Language)
    Wikipedia


    --- Добавлено ---

    P.S. Прошу не считать это наездом на Laravel или Eloquent. Просто мне кажется, что вы не до конца понимаете о чём пишете.
    В любом случае вы молодец.

    Я за то, чтобы в этом разделе создать прикреплённую тему с полезными ссылками и разместить там в т.ч. ваш "советник" :)
     
    #6 artoodetoo, 12 ноя 2017
    Последнее редактирование: 15 ноя 2017
  7. Alexey Mezenin

    Alexey Mezenin Новичок

    С нами с:
    27 апр 2016
    Сообщения:
    17
    Симпатии:
    2
    Тэйлор говорит о том, чтобы вывести работу с данными из контроллеров. Я в "Хороших практиках" и статье говорю о том же. Разница только в том, что он приводит пример отдельного класса-репозитория, а я храню работу с данными в классе-модели. Т.е. класс модели выступает в роли репозитория. Использовать еще один уровень абстракции здесь бессмысленно, плюсов это не дает, а минусы видны по сотням проблем, описанных в вопросах на StackOverflow. В то же время, я советую использовать классы-репозитории для сырых SQL запросов и при работе с Query Builder.

    Давай "на ты"? Посмотри еще раз на два примера в репо. Ты же не будешь спорить, что вариант ОРМ действительно несравнимо более читаемый? Другими словами, изменить Eloquent вариант, не сломав существующий запрос и функционал, который работает с результатом, очень легко. Прочитать, изменить код, протестировать займет в разы или десятки раз меньше времени, а на выходе будет все та же коллекция. В случае огромным SQL, читается он не так легко, зато допустить ошибку легче (дополнительное время при тестировании) и при изменениях часто придется менять код, который работает с результатом.

    При этом, в примере из "Хороших практик" достаточно простой пример, в реальных приложениях есть просто монструозные Eloquent запросы, которые при этом отлично читаются. Такой запрос генерирует простыню из десятка сложных SQL запросов.

    Спасибо. Да, было бы здорово.
     
  8. artoodetoo

    artoodetoo Суперстар
    Команда форума Модератор

    С нами с:
    11 июн 2010
    Сообщения:
    11.106
    Симпатии:
    1.243
    Адрес:
    там-сям
    класс таблицы AR в роли репозитория? не убедительно :)

    давай. вариант с AR может быть более коротким в простых случаях. но давай вернёмся к твоему конкретному примеру: он фальшивый, потому что так запросы не пишут. моя претензия в этом. всё остальное это уже вкусовщина.

    я стараюсь не думать о том, какой фиговый запрос может генерировать ORM. время разработчика более ценный ресурс чем процессорное время (хочется верить :D )
    НО если мы сравниваем SQL с тем как это может выразиться на Eloquent, то запрос надо брать настоящий, написанный руками для правдоподобной задачи. иначе это не пример, а подмена, демагогия.
    --- Добавлено ---
    давай возьмём жизненный пример: несколько агрегатных функций в одном запросе, даже без джойна:

    Код (Text):
    1. SELECT
    2.   manager_id,
    3.   COUNT(*) AS appt_count,
    4.   MIN(booking_time) AS min_date,
    5.   MAX(booking_time) AS max_date
    6. FROM appointments
    7. GROUP BY manager_id
    согласись, читается это легко, как предложение на английском. сможешь показать как это более красиво выразить через AR?
     
    #8 artoodetoo, 13 ноя 2017
    Последнее редактирование: 15 ноя 2017
  9. Alexey Mezenin

    Alexey Mezenin Новичок

    С нами с:
    27 апр 2016
    Сообщения:
    17
    Симпатии:
    2
    Почему? Как надо по-твоему?

    Для меня твой пример кажется слишком простым, а мой как раз жизненным. Сужу я по своему опыту, конечно. Я прекрасно понимаю, что полно проектов, где SQL будет намного более разумным выбором, но использовать Laravel для этих проектов - это извращение.

    В случае с Eloquent, count, min, max берутся из загруженной коллекции без запросов в БД. Более того, ты можешь с легкостью фильтровать данные, не обращаясь к БД после основного запроса.

    Ну дак Laravel используется именно в проектах, где время разработки и поддерживаемость идут на первом месте.

    Согласен, но это слишком простой запрос. В реальных приложениях таких минимум. Да и даже этот пример будет выглядеть как-то так:

    Код (Text):
    1. $appointments = $manager->appointments()->get();
    2.  
    3. Total: {{ $appointments->count() }}
    4. Booking time from {{ $appointments->min() }} to {{ $appointments->max() }}
    Что читается как минимум не хуже.

    Еще, ты забываешь про методы вроде updateOrCreate, которые берут на себя тонну рутинного стандартного кода, mass assignment, soft deleting из коробки, accessors/mutators, касты, скоупы, события ORM и прочие вкусности, которые в реальных проектах экономят огромное количество времени (=денег) при разработке и при поддержке (особенно при поддержке).
     
    #9 Alexey Mezenin, 14 ноя 2017
    Последнее редактирование: 14 ноя 2017
  10. mkramer

    mkramer Суперстар
    Команда форума Модератор

    С нами с:
    20 июн 2012
    Сообщения:
    8.579
    Симпатии:
    1.760
    Так запрос от @artoodetoo делает совсем другое - там же группировка идёт по менеджерам. Как раз тот случай, когда я в проектах ухожу от любой реализации AR и делаю прямой запрос SQL - значительно быстрее отработает на большой таблице.

    Почему? В Laravel много всего полезного, кроме реализации паттерна AR, у меня есть проект, где AR для базы не используется (он мне там не очень удобен, к тому же проект перенесён с другого фреймворка), но используется огромное количество других фитч, типа посредников
     
  11. Alexey Mezenin

    Alexey Mezenin Новичок

    С нами с:
    27 апр 2016
    Сообщения:
    17
    Симпатии:
    2
    Извиняюсь, затупил. Но думаю, что мой посыл понятен. В реальном приложении задача как-то формулируется, например "загрузить менеджеров с их аппоинтментами":

    Код (Text):
    1. $managers->load('appointments'); // Загрузит аппоинтменты для каждого менеджера в коллекции
    Значит другая ORM используется? Я говорил про проекты, в которых сырой SQL действительно будет лучшим выбором, а либо очень сложные системы, либо проекты где архиважна скорость. В обоих счлучаях смысла использовать фреймворк нет.
     
    #11 Alexey Mezenin, 14 ноя 2017
    Последнее редактирование: 14 ноя 2017
  12. mkramer

    mkramer Суперстар
    Команда форума Модератор

    С нами с:
    20 июн 2012
    Сообщения:
    8.579
    Симпатии:
    1.760
    ORM не используется, свой код преобразует данные из базы в объекты бизнес-логики. Используется построитель запросов очень активно.
     
  13. Alexey Mezenin

    Alexey Mezenin Новичок

    С нами с:
    27 апр 2016
    Сообщения:
    17
    Симпатии:
    2
    Мы говорим про реальное коммерческое приложение или пет? Подскажи, почему ты выбрал использовать Query Builder, а не сырые SQL запросы или ORM?
     
  14. mkramer

    mkramer Суперстар
    Команда форума Модератор

    С нами с:
    20 июн 2012
    Сообщения:
    8.579
    Симпатии:
    1.760
    Реальное приложение. Не стал брать AR, потому что достаточно сложная организация таблиц (архитектуру БД проектировал другой человек), и требуется сделать довольно много действий, чтобы преобразовать записи БД в сущности, с которыми будет работать программа. Query Builider выбрал потому, что его удобно прогонять через разные классы для вариативного построения запросов (реализация фильтрации). Со строкой запроса такое не сделать.
     
  15. Alexey Mezenin

    Alexey Mezenin Новичок

    С нами с:
    27 апр 2016
    Сообщения:
    17
    Симпатии:
    2
    Ну вот, SQL уже не выбрал, уже хорошо. На счет QB можно сказать, что у тебя особо выбора не было? А если бы ты писал этот же проект клиенту по уму и с нуля ?
     
  16. mkramer

    mkramer Суперстар
    Команда форума Модератор

    С нами с:
    20 июн 2012
    Сообщения:
    8.579
    Симпатии:
    1.760
    Я думаю, AR бы там тоже не было. Или был бы, но в качестве вспомогательного средства. В принципе, структура базы не такая плохая, хотя я бы чуть-чуть по-другому сделал.
     
  17. artoodetoo

    artoodetoo Суперстар
    Команда форума Модератор

    С нами с:
    11 июн 2010
    Сообщения:
    11.106
    Симпатии:
    1.243
    Адрес:
    там-сям
    Ну никак это не аналог того простого SQL, сорри. Прямо расстроил меня :D

    Во-первых, это не работает. :) Во-вторых, это никак не меньше четырёх запросов. И в-третьих, это про одного менеджера, а не про всех сразу, (ну или тут предполагается цикл и 1 + N*3 запросов

    Ужас-ужас вобщем. Для меня тема закрыта.
    --- Добавлено ---
    Пока пытался подобрать деликатные слова, тебя уже поправили.
    правильно, Максим! автор просто не то сделал (и даже это сделал с ошибками).
    но дело даже не в эффективности. тут просто не хватает возможностей AR. слабО ему! если и можно выкрутиться, то с кучей DB:raw и что тогда останется от "красоты"?
     
  18. Alexey Mezenin

    Alexey Mezenin Новичок

    С нами с:
    27 апр 2016
    Сообщения:
    17
    Симпатии:
    2
    Что не работает то объясни. Сформулируй бизнес задачу своего кода.

    Код, показанный выше - это два запроса без N+1 и, тем более, без 1 + N*3. Я же там четко написал, что эти функции не создают запросы в БД, а работают с загруженной коллекцией.

    Два запроса - это достать менеджеров и достать аппоинтменты. Если менеджеры уже есть в виде коллекции или IDшников, тогда будет один запрос.

    Дак я скачу от бизнес задачи, а не данного SQL. Зачем делать клон сомнительного запроса? Ни одна бизнес задача не звучит как "Сагреггировать минимальную и максимальную дату и бла бла бла сгруппировав по manager_id бла бла бла". Бизнес задача может звучать как "Отобразить мэнеджеров и их аппоинтменты, показав самую раннюю и позднюю даты". С Eloquent/коллекциями даже такая наипростейшая задача решается намного элегантнее и, что самое важное, дешевле. Ну а более сложный пример реальной задачи я в репо привел. Это реальная задача из реальной CRM, которую я разрабатывал.
    --- Добавлено ---
    А что было бы? Другой фреймворк? Laravel + другая ORM? Или все тот же QB?

    Если QB, то чем ты руководствуешься при его выборе (вместо ORM)?
     
    #18 Alexey Mezenin, 14 ноя 2017
    Последнее редактирование: 14 ноя 2017
  19. mkramer

    mkramer Суперстар
    Команда форума Модератор

    С нами с:
    20 июн 2012
    Сообщения:
    8.579
    Симпатии:
    1.760
    Я думаю тот случай, когда по-любому была бы своя реализация хранилища. Не обязательно же пользоваться прямо каждой фитчей фреймворка. Вот Laravel имеет Broadcasting в своём составе, а передо мной такой задачи ещё не ставили. Значит ли, что если мне не нужен Broadcasting, мне не нужен Laravel? С Eloquent та же точно история. Если я не хочу его использовать, это не значит, что я не должен использовать Laravel.
    Дешевле загрузить всю базу в коллекцию, и потом чего-то там считать, чем сделать запрос, который, при наличии индексов, отработает очень-очень быстро?
     
  20. Alexey Mezenin

    Alexey Mezenin Новичок

    С нами с:
    27 апр 2016
    Сообщения:
    17
    Симпатии:
    2
    Спасибо, понял.

    Это другая плохая практика, описанная в моем репо. Не использовать велосипеды. Дело в том, что клиент в таком случае заплатит за разработку и поддержку проекта больше, чем если бы ты использовал стандартные инструменты, а не франкенштейна. Вот сделал ты свой велик, клиент тебе заплатил $3000 вместо $0 за это (ORM/коллекции уже есть, а ты свое хранилище писал). Дальше, пришел человек слегка изменить функционал и вместо того, чтобы переписать несколько строк, он сидит и изучает твой велосипед. Потом делает правки и ломает что-то, естественно, потому что твой велик он только что изучил и он просто не может на 100% в нем ориентироваться, не поработав с ним месяц-другой. Клиент заплатил разработчику $2000 вместо $100.

    Я нигде не "гружу все", еще раз, я скачу от бизнес задачи "Показать всех менеджеров и их аппоинтменты", как пример. artoodetoo назвал мой пример не реальным, а свой реальным, я с этим в корне не согласен.

    Мы можем сформулировать реальную задачу (бизнес задачу) и написать код, чтобы сравнить ORM и SQL. Конечно же, здесь можно схитрить и показать в более ярком свете как ORM, так и SQL, но общая картина думаю ясна.

    Я вообще не понимаю спора SQL против ORM в 2017 году.
     
    #20 Alexey Mezenin, 14 ноя 2017
    Последнее редактирование: 14 ноя 2017
  21. mkramer

    mkramer Суперстар
    Команда форума Модератор

    С нами с:
    20 июн 2012
    Сообщения:
    8.579
    Симпатии:
    1.760
    Не каждый инструмент подходит для конкретного случая. Там, где AR удобен, я с удовольствием им пользуюсь.
    И, соответственно, надо загрузить в коллекции всех менеджеров и все их аппоинтменты. Ну или сделать кучу раз вызов count(), который приведёт к куче запросов. Конечно, есть такая штука: https://laravel.com/docs/master/eloquent-relationships#counting-related-models, но запрос от @artoodetoo делает больше гораздо за одно обращение к БД.
     
  22. Alexey Mezenin

    Alexey Mezenin Новичок

    С нами с:
    27 апр 2016
    Сообщения:
    17
    Симпатии:
    2
    Я же два раза уже написал, что не приведет. Будет работа с коллекцией. Здесь методы max(), min(), count() - это не методы QB, это методы коллекций.

    Собственно, я об этом и писал выше. Есть задачи, где SQL предпочтительнее: системы статистики, высоконагруженные API и пр., но это не про Laravel. На данный момент я видел больше сотни реальных приложений (если считать то, что присылают кандидаты для оценки) и нигде SQL не был в тему. При этом, SQL использовался только там, где уровень разработчика был ниже плинтуса.

    И еще, все до сих пор слепо ругают Eloquent/RoR за AR (примерно также ругают PHP), но вот я пользуюсь Eloquent и нигде он мне еще дорогу не перешел. Что именно не так с Eloquent? Интересна не теория, потому что это opinion based, а именно минусы этого ORM в конкретной задаче.
     
  23. artoodetoo

    artoodetoo Суперстар
    Команда форума Модератор

    С нами с:
    11 июн 2010
    Сообщения:
    11.106
    Симпатии:
    1.243
    Адрес:
    там-сям
    Значит фейл происходит потому, что всё слишком просто?!

    Ага, то есть предполагается, что ты скачал в коллекцию полный набор записей данного менеджера (!!!). А для всего множества менеджеров, соответственно, надо будет прокачать все записи вообще.
    Алексей, SQL это язык работы с множествами, а AR это имплементация идеи "запись таблицы" плюс пара полезных фишек — разного поля ягоды. Ты пытаешся квадратные колышки запихать в круглые дырочки и не понимаешь как это нелепо выглядит. Лучше остановись.

    Другая ошибка это утверждение "класс модели выступает в роли репозитория". Ну не надо считать, что менеджер доступа к базе и хранилище бизнес объектов это одно и то же. Был бы data mapper… впрочем на phpclub.ru тебе лучше меня объяснят. Я вижу там ты тоже в несознанку играешь.

    ИМХО, не надо тебе писать инструкции для новичков. Может ты и придёшь к успеху, но получится второй Евгений Попов, а не Fabien Potencier.

    Я закончил на этом. Peace!
     
  24. Alexey Mezenin

    Alexey Mezenin Новичок

    С нами с:
    27 апр 2016
    Сообщения:
    17
    Симпатии:
    2
    Я задавал вопрос "в чем конкретно преимущество использования репозитория при работе с Eloquent", мне десятки людей так и не ответили. Ответишь? Только не пересказывай теорию из Java книжек 2000х, а конкретно, чем плохо вызывать методы из класса Eloquent модели?

    Ты меня phpклубом на место хочешь поставить? А что, там супер профи сидят? Я за полтора года дошел до 2x-5x рейта этих ребят, которые строят из себя богов, а на деле часто охинею несут. Это вообще уникальный ресурс, где царят грубость, оскорбления и дедовщина. Не удивительно, что он давно умер.

    Да, разговор у нас не клеится, ты переходишь на личности, вместо того, чтобы привести аргументы. При этом видно, что порой не знаешь о чем говоришь (например 1 + N*3).
     
    #24 Alexey Mezenin, 14 ноя 2017
    Последнее редактирование: 14 ноя 2017
  25. artoodetoo

    artoodetoo Суперстар
    Команда форума Модератор

    С нами с:
    11 июн 2010
    Сообщения:
    11.106
    Симпатии:
    1.243
    Адрес:
    там-сям
    Отвечаю свою версию: репозиторий это не догма, не хочешь, не используй.
    Принципиально он отличается от записи AR тем, что не содержит команд непосредственно отвечающих за интерфейс к БД, как в Eloquent. Можно конечно свести всё к абсурду, вводя какие-то промежуточные понятия, но это как раз "плохая практика". Изначально бизнес-объект не связан с базой вообще никак! Его сохраняют внешние службы.


    Ах Алексей, объяснять очевидное труднее всего. Просто заставь свой абстрактный пример работать и отследи запросы.
    EDITED: Выливается в два варианта и оба ужас-ужас:
    - с тремя агрегатами, которые eloquent реализует через три запроса ("N*3" но маленькие),
    - с коллекциями дочерних записей ("N" но большие)
    и "+1" один это чтение таблицы менеджеров, которая в исходном запросе вообще не нужна
    Лучше застрелиться, чем так палиться!
    --- Добавлено ---
    а отправная точка какая, продавец, маркетолог? рискую и правда перейти на личности, но скажу, что есть у меня ощущение, что обща.сь с продажником.
     
    #25 artoodetoo, 14 ноя 2017
    Последнее редактирование: 14 ноя 2017