«РНР — это навсегда»: что нужно знать об одном из самых влиятельных языков веб-разработки
Поговорили о том, как развивался, падал и вставал РНР, за что его ругают и почему его не заменит ни один другой язык программирования (даже Go).
Иллюстрация: Colowgee для Skillbox Media
Олег Шабашов
Разработчик в компании Searchanise. Пишет на РНР, Go, Java, React.
Содержание:
Как влюбиться в РНР
— Как ты пришёл в IT?
— Я начинал монтажником локальных сетей, потом работал инженером-эникейщиком по вызову. На каком-то этапе потребовалось автоматизировать часть своих действий, и в качестве первого языка программирования я выбрал зубодробительный Perl со всеми его прелестями — высоким уровнем входа, не самым лёгким синтаксисом и так далее. На РНР перешёл из-за того, что он более развитый, но при этом у него ниже входной порог. Да и, чего греха таить, было больше вакансий с ним. Начал, по-моему, версии с четвёртой, которую ещё сам Расмус активно контрибьютил.
Как и раньше, РНР можно охарактеризовать как динамично развивающийся язык веб-сайтов и веб-сервисов. Мне нравится, что он позволяет быстро создавать прототипы с помощью стабильных библиотек и фреймворков. Изначально это был просто набор сишных скриптов для обработки HTML-шаблонов, и он оказался удобнее и привычнее, чем тот же Perl, для всех, кто когда-то имел дело с языком C.
— В чём главные фишки РНР? За что его можно полюбить?
— Тема, на самом деле, довольно холиварная. Ведь динамическая типизация, которую чаще всего указывают как главную фичу РНР, — это палка о двух концах: она вызывает как огромную любовь, так и лютую ненависть. Лично мне нравится, что она позволяет очень быстро, не особо углубляясь в строгое построение архитектуры и выстраивание дата-контрактов, сделать прототип, запустить его, посмотреть, насколько он рабочий, а дальше уже рефачить в статическую типизацию.
С другой стороны, можно включить так называемый строгий режим, и всё станет совсем по-другому: придётся писать изначально хороший, нормально поддерживаемый код. Сам интерпретатор не даст его скомпилировать и упадёт в конвульсиях на любой ошибке: «А-та-та, не делай так, пожалуйста». Очень удобно, что этот режим при рефакторинге, например, библиотеки будет распространяться не на клиента, который может её использовать, где-то подключать себе через Composer и так далее, а только на собственную библиотеку разработчика. Благодаря этому можно потихонечку избавляться от legacy и рефакторить код.
— Какой тулинг сложился вокруг РНР, какие IDE его поддерживают, какие редакторы кода принято использовать?
— В первую очередь вспоминаются ребята из JetBrains, которые написали PhpStorm. Честь им и хвала за эту IDE, в которой всё работает сразу, «из коробки»: не нужно ничего настраивать, устанавливать какие-то плагины и так далее. Тем не менее у нас в команде ребята пишут и в Vim, и в VS Code. Они просто ставят нужные себе плагины для проверок (например, Psalm) и прогонов тестов — и всё нормально. Хотя те, кто пишет сегодня на РНР в Vim, — это, по-моему, монстры какие-то: они помнят такие клавиатурные сокращения, которые я даже боюсь представить.
Если говорить об установщиках пакетов — на ум прежде всего приходит Composer, который просто поборол предыдущий установщик PEAR. И это хорошо, потому что Composer стабильно работает везде и всегда. Разумеется, не стоит забывать про линтеры: они, насколько я помню, теперь уже встроены в язык, так что можно не ставить дополнительных тулзов для проверки синтаксиса, чтобы проверить не упадёт ли где скрипт из-за забытой точки с запятой. Удобно, кстати, на CI прогонять перед запуском тестов. И конечно, стоит упомянуть PHP Unit — основной тестовый фреймворк для написания тестов на РНР.
Немного о соперниках
— Какие языки можно назвать конкурентами PHP? Чем РНР лучше их, чем хуже?
— Ещё один холиварный вопрос. Тут, понятное дело, сразу всплывает Go. Два-три года назад был просто адский бум, все кричали: «Game over — РНР закапываем, достаём Go, на нём всё напишем». Действительно, на Go есть классные фреймворки, инструменты и сервисы — хороший язык, никто не спорит. Но, на мой взгляд, он не может полностью заменить РНР в плане быстрого прототипирования и разработки, хотя и неплохо дополняет его.
Ты просто разворачиваешь сервис на Go, обмазываешь его сверху REST и говоришь: «РНР, смотри, вон сервис, который работает очень быстро, очень параллельно, жрёт мало памяти, хорошо относится к таскам, которые завязаны на процессор. Пожалуйста, используй его». Даже сетевые издержки на взаимодействие между РНР и Go составляют какие-то миллисекунды — это быстрее, чем то же самое делать на РНР.
Скажу больше: года полтора назад я устал от РНР и думал полностью перейти на Go. До этого писал на нём дополнительные сервисы, доводил что-то до продакшена, выносил из кодовой базы РНР какие-нибудь медленные сервисы и переписывал их на Go — они становились быстрее. Но вскоре выяснилось: когда начинаешь писать на Go код уровнем выше мидла, сразу чувствуется разница с РНР — естественно, в пользу последнего. В РНР ты сразу видишь, где у тебя класс, где интерфейс, а в Go — нет. Смотришь на struct и думаешь: «А от кого он наследуется? Как он имплементируется? Там сверху есть что-нибудь?» И ты такой: «А, чёрт, надо искать, лезть в документацию…»
Опять же, лет семь назад все хотели перейти на Ruby и Ruby on Rails, включая гигантов вроде Twitter. Потом вернулись обратно, потому что упёрлись по памяти. А четыре года назад все кричали: «Добро пожаловать на Node.js и Event Loop, там всё хорошо, есть поток, есть асинхронность, РНР больше не нужен». Но потом вышли седьмая и восьмая версии РНР — и сейчас я не вижу толпы программистов, которые пишут бэк на Node.
Сейчас потихонечку заходит мода на Rust, каждый второй человек мне говорит: «А вот Rust умеет вот это» — ещё одна волна пошла. Поживём — увидим.
Как РНР стал великим опять
— Если посмотреть на историю языка, то, судя по моему общению с разработчиками, пятую версию некоторые чуть ли не ненавидят, а про восьмую говорят: «Вот она классная, суперская, интересная, очень современная». Что за это время поменялось?
— Разработчики перепрыгнули одну версию — пилили-пилили «шестёрку», потом решили: «Нет, будет „семёрка“». Переписали движок, получили в каких-то тестах чуть ли не двойной прирост в скорости, уменьшили потребление памяти. А при переходе с «семёрки» на «восьмёрку» ребята просто посмотрели по сторонам, взяли всё самое лучшее и подтянули к себе: те же атрибуты, файберы, синтаксический сахар… То есть как бы провозгласили: «Давайте сделаем РНР великим опять».
Я делал в своей команде доклад про изменения в версиях с 7.4 по 8.1. Так вот: у меня просто горит — так я хочу использовать эти изменения везде. Например, я уже не понимаю: а как мы раньше делали перечисление без enum? Или, допустим, enum плюс новый оператор match — это же просто праздник какой-то!
— Как выглядит процесс перехода с одной версии языка на другую, насколько он болезненный, какие этапы приходится проходить?
— Процесс болезненный, само собой. Много функций объявляются устаревшими. Особенно тяжело переходить, когда у вас есть семилетний legacy-код. Благо, спасают всякие тулзы, которые всё просканят и покажут, что где нужно исправить, а иногда даже исправят сами, автоматически. Но, допустим, когда у вас Laravel, та же «шестёрка», а вы хотите обновиться на «девятку», нужно использовать утилиты вроде Laravel Shift. Конечно, придётся отдать деньги, но оно того стоит. Или можно взять Rector.
А без инструментов придётся самостоятельно искать и вычищать устаревшие вызовы. С другой стороны, в том же PhpStorm можно запустить инспекцию по всему коду, выборочно выгрузить инспекции, посмотреть, что IDE указала как deprecated, и потом уже убирать.
Какие у PHP есть фреймворки и что выбрать
— Какие в мире РНР существуют фреймворки? Пробежимся кратко по каждому.
— Безусловный лидер — Symfony, Laravel — номер два в России, а также Yii 1 и Yii 2.
Symfony — фреймворк, который, по моему мнению, нацелен на большие, сложные enterprise-штуки. Он сам по себе довольно большой, развесистый, в нём очень много бандлов, и в этом есть как плюсы, так и минусы. К плюсам я отношу надёжность, хорошую документацию, прекрасную поддержку сообщества и то, что он нацелен на безопасность: можно, например, вспомнить либу SensioLabs, она же есть для Composer, которая сканит зависимости и показывает, есть ли в них какая-либо уязвимость.
На втором месте Laravel, которая одновременно подкупает и отталкивает своей магией. Сначала все говорят: «Ой, фу, магия, на этом же невозможно писать». Но они забывают про экосистему Laravel и невероятное количество тулзов, написанных для неё — тех же Passport, Jetstream, Sanctum… Очень много всяких штук, которые просто ставятся из Composer и работают. Или та же Nova, которую мы использовали в этом году, натравили на наши модельки и получили новую классную админку, в которой можно просто за два клика менять какое-либо поведение. Нам даже не пришлось дёргать ребят-фронтендеров! Nova меня очень приятно удивила. Кстати, у них вышла поддержка тёмной темы — можете, в общем, не писать свои кастомные CSS.
Yii — это такой фреймворк в себе, известный, по большому счёту, только среди разработчиков из СНГ. Я лично писал сначала на первом Yii, потом на втором, не дождался выхода третьего и ушёл в плавание по всем остальным фреймворкам. Я его тепло люблю и немного разочарован, что «тройка» до сих пор не вышла.
— Как ты выбираешь фреймворк на проект? Или у тебя есть просто какой-то фаворит?
— Раньше это был Yii 2, я его брал всё время. На нём очень удобно создавать модели из базы, потому что Gii работает просто отлично. Это такой маленький укол в сторону Laravel и его генераторов. Но когда разрабатываешь проект дольше года и он становится развесистым, накапливается много логики, то на Yii 2 приходится либо модули использовать, либо выкидывать сервисный слой, но у этого решения тоже есть свои минусы.
Поэтому сейчас я исхожу из ситуации и знаний команды. К примеру, если вся команда подкована в каком-то одном фреймворке, просто берём новую версию. Если же участники скилловые, но каждый в своём, выбираем, что называется, по проекту. Много безопасности, серьёзных работ с базой — берём Symfony. Нужно быстро развернуть какой-то прототип, который потом уйдёт в продакшен и будет поддерживаться всей командой, — берите Laravel, и будет вам счастье. Да, у него вход не такой простой, как у второго Yii или у Symfony, но это окупается. Брать ли сейчас второй Yii, я не знаю. Я бы, наверное, не стал.
Какие перспективы у PHP
— Какие, на твой взгляд, у РНР перспективы в современном мире? Будет ли он расширять свою популярность или будет медленно, постепенно угасать и превратится в какой-то немножко маргинальный и экзотический язык для поддержания и развития legacy либо будет использоваться в каких-то очень нишевых проектах?
— Чтобы популярность языка угасла, вся существующая в мире кодовая база на РНР должна стать совместима с каким-то новым языком, который будет круче, лучше, но при этом будет иметь тот же синтаксис. Я не знаю, как это может произойти, учитывая скорость, с которой развивается PHP, появляются новые фичи, повышается стабильность и производительность, уменьшается потребление памяти. Становятся распространёнными такие классные штуки, как ReactPHP, который не самый простой в применении, но даёт вам РНР-синтаксис, многопоточность, многопроцессность. Используйте, почему бы нет?
В общем, я сильно сомневаюсь, что язык хоть куда-то денется. Думаю, что с учётом текущей скорости и трендов он будет только развиваться. Сейчас «восьмёрка» везде встанет, потом будет 8.5, потом будет «девятка».
— На твой взгляд, уход Никиты Попова из команды разработки PHP — это хорошо или плохо?
— Думаю, скорее плохо: человек достаточно известный, много контрибьютил, привнёс в язык хороший boost развития. Но что поделаешь — люди хотят заниматься ещё чем-нибудь. Почему бы нет?
— С другой стороны, его уход спровоцировал создание PHP Foundation. Вроде как туда начали вкладывать деньги, появилось более значительное количество разработчиков, bus-фактор как будто бы немножко устранился. Станет ли это каким-то новым драйвером развития?
— Сложно сказать. Хочется верить, что это станет новой вехой в развитии РНР — по крайней мере, на первых порах, конечно, пока у всех есть энтузиазм и деньги. Можно привести в пример дистрибутив Ubuntu, в который компания Canonical однажды бахнула очень много денег. И он взлетел, стоит теперь на всех серверах и десктопах и неплохо подпирает Red Hat с его энтерпрайз-моделью. Я думаю, компании вроде Jetstream и Badoo будут и дальше заинтересованы в развитии РНР и, возможно, даже продолжат донатить на его развитие.
Что нужно знать начинающему PHP‑разработчику
— Что надо знать джуну в РНР, чтобы получить первую работу? Как ему подняться до мидла, сеньора?
— В первую очередь — синтаксис, основы языка: как он вообще работает, где применяется, что такое веб-сервер, чем интерпретируемый язык отличается от компилируемого, что такое интерпретатор и так далее. Не помешает небольшая начитанность про какой-нибудь из фреймворков. Я думаю, этого будет достаточно и мы такого человека к себе возьмём.
Чтобы стать мидлом, нужно уметь всё, что делает джун, и вдобавок знать хотя бы один фреймворк. Было бы огромным плюсом, если у человека есть какой-нибудь pet-проект, который он начал, ковыряет каким-то образом. То есть не просто пишет код, за который ему платят, а ещё и развивается, трогает какую-то технологию в свободное время.
Ещё одно преимущество — если мидл умеет писать тесты и понимает, что такое стандарты кодирования в РНР. Необязательно владеть всеми типами тестов, но неплохо сделать хотя бы юниты на свой код, к примеру.
И, пожалуй, я бы взял человека, даже не глядя на остальные качества, если у него есть желание развиваться. Например, он только услышал про новую технологию — и у него прямо руки трясутся: «Хочу попробовать, изменить, написать интеграционный тест, чтобы база не упала».
Сеньор-разработчик знает несколько фреймворков, но не использует ни один из них, потому что он фреймворк-агностик. Кроме того, ему нужно освоить ещё какой-нибудь язык, хотя бы на начальном уровне. Go — прекрасно, React — хорошо: теперь он знает ещё один подход к программированию, понимает, что такое алгоритмы, паттерны. А самое главное — применяет их, когда нужно, а не просто по принципу: «О, я знаю Chain of Responsibility, и давайте я теперь буду чейнить методы, смотрите, какой я крутой».
Кроме того, сеньор должен знать про смежные технологии. Допустим, понимать, чем Redis отличается от Rabbit и что лучше использовать в конкретной ситуации. Или почему у него сообщение с одного сервиса не дошло до другого, кто в этом виноват и куда копать.
Приведу аналогию с огородом, которую мне как-то рассказал один из тимлидов. Джун умеет просто копать грядку. Мидл знает, что грядок несколько и умеет копать несколько грядок одновременно. А сеньор, копает весь огород, знает, где какая грядка, и понимает, что рядом ещё два-три огорода. Плюс он приглядывает за джунами и мидлами, естественно.
Типичные ошибки разработчиков
— В чём чаще всего ошибаются разработчики?
— Наверное, самая частая ошибка, которую я встречаю, — over engineering, когда ребята используют малораспространённые и редко используемые возможности языка. Чтобы разобрать такой код, нужно открыть документацию, посмотреть, что конкретно делает вот эта функция или этот подход. Да, разработчик сократил, к примеру, две строчки кода, вместо пяти стало три. Но время на чтение такого кода увеличивается. А мы ведь пишем не для процессора, а для других разработчиков. Так что я скорее против подобных излишеств.
Глубокое знание языка хорошо, когда начинаются проблемы — например, вы упираетесь в потолок по производительности. В таком случае я могу приветствовать, если люди находят узкое место и выносят его куда-нибудь отдельно. Пишут вокруг него какой-нибудь сервис, к примеру, и дальше уже подробненько, используя какие-нибудь низкоуровневые редко используемые штуки, решают эту проблему. Естественно, с навешенным тестом или с хорошим комментарием о том, что здесь происходит.
— Насколько сильно среднестатистический РНР-разработчик вовлечён в работу с legacy, в какой-то рефакторинг?
— Это боль. Вы работаете в компании с legacy всегда, если только вас не послали в какой-то стартап, который только вчера сделали. Например, я посвящаю этому не меньше 70% своего времени. В этом нет ничего плохого, как раз legacy и дало компании денег, чтобы нанять вас.
Тут ещё стоит учитывать интересы самой компании: некоторые спокойно живут с legacy и не хотят его переписывать. Тебе не дадут на это ни времени, ни денег, ни ресурсов, а колбасить по выходным — удовольствие так себе.
Что почитать про РНР
— Как ты обновляешь знания по РНР, по фреймворкам, что читаешь, за кем следишь, откуда получаешь информацию?
— Периодически пролистываю «Хабр», потому что там попадаются действительно годные вещи, про которые ты узнаёшь и думаешь: «Ох, ни фига себе! А что, так можно было что ли?» Причём это даже не обязательно будет связано с РНР. Бывает, просто читаешь про какой-то язык, технологию, инженерный подход, и тебя осеняет: «Блин, а можно ведь и у нас так же сделать!»
Например, недавно была статья от ребят из VK про то, как они заюзали бинарный протокол protobuf, ушли от TCP в сторону UDP — и неплохо так ускорились. Мне стало интересно, потому что protobuf — достаточно любопытная штука (привет, Golang!).
Кроме того, на «Хабре» есть очень классный дайджест непосредственно по РНР. Всегда читаю его полностью, открываю сразу по пять-шесть ссылок.
Если встаёт выбор какой-нибудь технологии, подхода или хочется просто почитать новую книгу, сильно помогает список Awesome на GitHub. Там всё разбито по языкам и технологиям, они ранжированы, везде проставлен рейтинг, значки «Open Source / не Open Source», «платно/бесплатно» и так далее.