Pull to refresh
4
0

Web backend developer

Send message

типичный CRUD без логики это бессмысленно. 

Где "круд без логики"? Я писал про задачи рода "типичный круд плюс много логики", – и здесь нет проблем раскидать логику в те же сущности и/или сервисы. Но необходимость круда при этом никто не отменял (по крайней мере, в тех случаях о которых я пишу и которые решает платформа).

она заточена на REST и CRUD-действия, что для большинства реальных приложений не подходит.

Кажется, об этом и речь. Может быть, у вас основной пул задач в контексте приложения, где не нужен круд, а кол-во роутов = кол-во бизнес-сценариев. В таком случае ценность платформы уменьшается, конечно. Я пишу про то что вокруг очень много задач, где нужно всё вместе: и почти 100% круд на всё, и ещё логика в добавок. "Показать список всех заказов", "добавить нового курьера", "удалить тариф", "показать все мои транзакции и баланс", – это не бизнес-процесс, а обычный круд. И он всегда будет там, где нужно что-то отображать конечному пользователю (не говоря уже про "админов" с ещё десятком разных ролей).

Я пока не видел исследований большинства пхп-проектов где бы сравнивали "покрытие сущностей крудом", может быть у вас есть ссылка на такое если утверждаете что "для большинства"?

В сущности есть поле created_at, а в фильтре 2 поля "от" и "до"

В фильтре галочка "has_images", а в сущности такого поля нет

В фильтре есть поле "search_text", и оно должно искать по нескольким текстовым полям сущности

Все эти фильтры уже есть из коробки в apiplatform, которые можно настроить одной строкой там же.

Вот кстати фильтрация по любым полям обычно нужна когда бизнес-логика находится на клиенте.

В таблице заказов будете делать десяток полей ввода для поиска по маске карты/фио/id/трекномеру на половину страницы? Или всё-таки один, который будет искать по всем полям одновременно? Можно и на клиенте решать по каким точно параметрам искать, можно и решить это на стороне сервера, – уже зависит от фантазии клиента, удобство в том что на бэке не надо делать ровно ничего для этого.

60 строк кода, ага. А как насчёт кода внутри RegistrationForm? А вот это $validationResult->getDto()? `successResponse()`? И это только для всего двух роутов регистрации/логина. Дорисуйте остальную сову?

---

Теперь представим что у вас 30 сущностей и для всех из них нужен типичный CRUD с разделением доступа по 3-4 ролям.

С подходом от APiPlatform я добавлю 30 аннотаций с security параметром и всё (1-4 строки для каждой сущности). И может накину два кастомных контроллера для очень специфических роутов.

Вы же сделаете 30 сервисов и 30*4 контроллеров (ну или 30 контроллеров с 4 методами в каждом по вкусу), в котором будет примерно один и тот же код? Да ещё и самописный, а не оттестированный тысячами пользователей?

Теперь добавим фильтрацию по любым параметрам, например, которая должна работать везде – сколько кода займёт это в вашем подходе? Явно не по одной строке для каждой сущности (в ApiPlatform именно так).

---

Я это к тому что для каждой задачи свой инструмент. И если в ваших проектах используется 5-6 сущностей со сложной логикой в каждом роуте – ApiPlatform ничего не упростит. Но если у вас большой проект с кучей сущностей и связей между ними и нужен разнообразный CRUD, то оно сэкономит очень много времени разработки и тестирования.

> Получается, что в вы актуализируете постоянно кеш данных, к которым идут запросы очень редко.

Нет. Цитирую:«Ленивость и экономия памяти обеспечивалась логином: если за некоторый период юзер не логинился, то его кэш очищается.».

Это не серебряная пуля, я топлю за анализ поведения системы перед тем как его менять (-:
В моём случае я знаю что юзеров (которые логинились хотя бы раз за последние два дня) в среднем около 30% и держать данные для них в кэше выгодно по этому кртерию. Возможно, в другой системе при других условиях я бы выбирал другой критерий.
Решал похожую задачу.

У меня был один TTL, только логика немного другая: TTL не влияет на выдачу (на запрос всегда отдаётся кэшированное даже устаревшее значение).
Однако, есть фоновая команда, которая периодически проверяет устаревшие значения и обновляет их. Так что фактический максимальный TTL = указанный TTL + интервал обновления + скорость обработки.
Ленивость и экономия памяти обеспечивалась логином: если за некоторый период юзер не логинился, то его кэш очищается.
(Может, для этой логики тоже есть термин?)

В итоге: нет проблемы «первого запроса» для активных пользователей, нагрузка фоновая, нагрузка равномерна (размазана по времени и не создаёт резких пиков), при нехватки памяти нагрузка не увеличится (просто реальный TTL будет меньше того что в конфиге).
1. Чтобы не было соблазна писать туда любой код и вообще делать конфиги слишком динамичными.
2. Связка PHPStorm + Symfony plugin = автокомплит прямо в yaml-конфиге. Будет ли он реализован и таким же удобным как в yaml? Сейчас я не вижу подсказок для php-конфигов.
3. Можно использовать конфиги на php (в 4 и 5 версиях) и все доки это учитывают.

Ссылка из поста, если я правильно понял, на PR о внутренних и библиотечных конфигах. У меня глаза кровоточили когда надо было заглянуть в конфиг symfony или бандла, а там внезапно xml.
Про первый спасибо, видимо, невнимательно прочитал и понял RFC неверно, печально, ждём.
Про второй – догдался сам когда уже написал сообщение. Наличие интерфейса типа `LikeableInterface` подойдёт в качестве нормального кода?

выходят фичи, которые помогают писать хороший код

В таком случае не вижу как UnionTypes «помогут» писать плохой код: его бы и так написали без типов вообще при отсутствии нормального ревью или при соответствующей политике команды. Может, «не предотвратят»?
Кажется, я чего-то не понимаю – что делаете без UnionTypes? Вот два примера:

class User
{
    public function getFriends() : Collection|User[] { /* ... */ }
}


class Like
{
    public function getTarget() : Post|Comment { /* ... */ }
}


Контекст примеров: какой-нибудь типичный CRUD на Symfony+Doctrine. Сейчас это решается вообще отсутствием возвращаемого типа и описанием в DocBlock.
Решить, конечно, можно.. но геморроя больше чем пользы.
В первом случае можно решить создав дофига типизированных коллекций, а в геттерах ещё и каждый раз в них оборачивать доктринские (она вставит в аттрибут всё-равно свою коллекцию) – уж не перебор ли?

Во втором можно разделить Like на CommentLike и PostLike, но я пока, видимо, не сталкивался с задачами, где лишние сущности имеют смысл – «общего лайка» было достаточно, да и код копипастить не нужно.


будет помогать писать некачественный код

А PHP и так сейчас помогает писать любой говнокод просто не используя типы. Но это ведь не значит что надо вдруг в обязательном порядке всех заставлять явно их указывать?
Почему зависимости, в основном, передаются через конструктор, а не в setter'ах?
Потому что безопасно. В случае передачи в конструктор любая ошибка не позволит создать объект, а, значит, он не успеет начать выполнять действия с ошибками. В случае с сеттерами есть возможность начать выполнять работу без зависимостей.

Для меня лично, вся разница (со стороны «потребителя кода SL/DI») выражается разницей между этими двумя примерами использования:
$logger = $this->container->get('logger'); // #1
$logger = $this->logger;                   // #2
$logger->debug('Blah-blah');               // #3

В первом случае есть проблемы: можно опечататься в строке названия сервиса, сервис может быть недоступен, не работает автокомплит (в связке symfony + phpstorm + плагин для symfony он таки есть, но это ведь частный случай), отсутствие сервиса или некорректный возвращённый объект доставят много весёлого времени дебага фатала в рантайме в третьей строке примера.

Во втором случае отсутствие сервиса станет заметно статически и до релиза, явный автокомплит, опечатки будут подсвечены средой разработки, при отсутствии сервиса тоже получите фатал, но зато будете знать где искать ошибку и (что самое главное, имхо) не будет выполнена некорректная работа или только её часть (откатить транзакцию из фатала… кхм… довольно проблематично).

Конкретно в Symfony есть удобство: достаточно в конструктор класса передать интерфейс/класс и магия автоматически заинжектит нужный сервис без нужды лезть в конфиги и описывать правила явно. Заодно сразу становятся видны архитектурные проблемы (ещё до релиза и даже до коммита правок) когда у конструктора 4+ параметра.

ps: было бы гораздо проще и понятнее следить за эволюцией мысли если бы выбрали примеры на одном языке (любом). Или был бы каждый пример оформлен в виде («вот так в пхп, а вот так в js»).
Спасибо! А что есть для тех, кто пишет серверные приложения для веба? Java, PHP, Ruby (Python и DotNet вижу)?
ЕМНИП, через Нестеров уже не пущают. Брал до «Чернышевское» этим летом, в Вильнюсе вошёл без проблем.
Я бы ещё добавил пример календаря, где есть дополнительный параметр, влияющий на выбор дат. В случае со Skyscanner'ом это цена билетов.
Скриншот


Так же в моей практике часто использовались быстрые ссылки вроде сегодня/завтра/через неделю, автоматически заполняющие календарь.
Спасибо за пост и особенно за комментарии!

Те же самые ощущения помешали мне в своё время всё автоматизировать с помощью ansible/vagrant. Брал даже готовые сборки с надеждой поменять какие-то мелочи (puphpet внезапно потребовал меньше всего напильника).
В конечном итоге, за неделю сделал три варианта деплоя (на разных стеках), в каждом из которых были мелкие, но очень неприятные проблемы, требующие какого-нибудь простого костыля.

Но это было два года назад. Как сейчас обстоят дела с готовыми «тематическими» сборками? Что-то вроде уже настроенных разбирающимися людьми ubuntu/nginx/php-fpm-7x/symfony/pgsql/xdebug/metrics/...? Для использования в простых проектах.
Не пользовался «зелёным», но пользуюсь в Питере «жёлтым» и работает нормально. В рамках центра – даже между станциями, на окраинах – только на станциях, но этого хватает.
В Мск вот ни «красный», ни «жёлтый» не ловят или ловят и телефон даже показывает 3G, но фактически связи нет никакой, даже на станциях – приходится использовать wifi.
Очень надеюсь, что наличие wifi в питерском метро не ухудшит ситуацию с сотой.
Хорошая подборка, пригодилась бы когда изучал.
А есть идеи для бэкендеров/серверов? Кроме crud api и cms/cmf.
А как выглядит у вас событие, например, UserChangeInfo? И где вызывается changeUserAll?
Благодарю, опробую. Если не будет тормозить как ST, то есть смысл и на него перейти. Удобный TUI лучше медленного GUI.
Век мануалы читай – всё-равно что-то пропустишь (-:
Спасибо!
Сильно тормозит если много изменений и, бывает, съедает почти Гб памяти.
Пользуюсь им только ради одной киллер-фичи – позволяет коммитить отдельные строки/блоки кода даже в рамках одного файла – JetBrains, например, не умеет, а как это делать консольно понятия не имею (но уверен, что не так удобно).
Опробовал, сравнил. Пробовал на трёх проектах, но результаты сравнимы поэтому в качестве примера приведу только один.

tl;dr: Infection генерирует больше мутантов, но «лишних» – количество выживших одинаковое. Кэширование в Humbug даёт лучшее ускорение, чем параллелизация в Infection.

В итоге, я не вижу для себя смысла переходить. Хотя, судя по статье, Infection понравился больше.




  • Исходные данные: средний проект, покрываться тестами начал уже после релиза в прод, новый код пишется после тестов (в основном юниты, но есть и «юзкейс-тесты», которые дёргают базу). Всего тестов 460, 2344 assertions, проходят за полторы минуты полностью.
  • Запуск. Infection сразу не завёлся. В Humbug я ставил таймаут 10 секунд. Infection начал работать только когда я выставил таймаут две минуты – время, большее чем время прохождение одного теста. Почему – не понял, но это не очевидно.
  • Отчёты. Humbug сохраняет в лог ещё и остальные метрики вроде MSI/MCS/покрытия, генерации и ресурсов. Infection – только диффы. Так что перед написанием коммента пришлось ещё раз полностью запустить Infection.
  • Скорость. Без ускорений Humbug быстрее: 1,15 часа против почти двух (из-за меньшего количества мутантов?). Без тестов трогающих базу, с кэшированием и параллелизацией Humbug опять же быстрее: 3-5 минут в среднем против 20 минут.
  • Мутанты. Infection сгенерировал на 30% больше мутантов (2360 против 1682), но количество выживших осталось ровно таким же (156). Эти «лишние» мутанты размазались между «убитыми» и «не покрыты тестами». MSI/MCS/Covered различаются на 1-2%.
Про Infection я узнал только из этой статьи так что полезных данных нет пока что. Но выглядит он интересно, так что в скором времени опробую и сравню (не уверен что на этой неделе), напишу.

Information

Rating
Does not participate
Date of birth
Registered
Activity

Specialization

Software Developer, Backend Developer
Senior
Git
OOP
PHP
Symfony
Nginx