Беручи PHP всерйоз

image
Ракета Союз, доставлена на поїзді на пусковий майданчик. Фото з суспільного надбання NASA.

Це переклад статті Taking PHP Seriously, автор якої є одним з інженерів відомого додатка Slack. Він розповідає про недоліки та переваги PHP, а також про мову Hack і віртуальної машини HHVM, на яку майже завершив перехід Slack.

Slack використовує PHP для більшої частини своєї внутрішньої логіки, що є не самим популярним вибором в наші дні. Чому ж ми вирішили написати новий проект саме на цій мові? Чи слід вам чинити так само?

Більшість програмістів, які трохи гралися з PHP, знають дві речі про нього: це погана мова, яку вони ніколи не стануть використовувати при наявності вибору, і що деякі з надзвичайно успішних проектів в історії світу використовують його. Це не зовсім протиріччя, але цей факт повинен змусити вас задуматися. Тобто, Facebook, Wikipedia, Wordpress, Etsy, Baidu, Box і останнім часом Slack — всі вони успішно вирішують проблеми, не дивлячись на те, що використовують PHP? Були б вони більш успішними, якщо б вони використовували у себе Ruby? Erlang? Haskell?

Цілком можливо, що ні. Мова PHP має безліч недоліків, які, безсумнівно, сповільнили його розвиток, але середовище PHP має такі переваги, які більш ніж компенсують дані недоліки. І він також має способи вирішення його власних мовних проблем, які цілком вражають. За підсумковими результатами, PHP надає найкращий фундамент для створення, зміни та експлуатації успішного веб-проекту в порівнянні з конкуруючими середовищами. Сьогодні я хотів би почати новий проект на PHP, з парою застережень, але не бачачи причин вибачатися за це.

Історичний екскурс
PHP народився в унікальній для сучасних мов середовищі веб-сервера. Його сильні сторони зв'язані з контекстом запиту на сервері.

PHP спочатку називався "Персональна Домашня Сторінка". Він був опублікований в 1995р. Расмусом Лердорфом, з націленням на підтримку малих, простих динамічних веб-додатків, начебто гостьових книг і лічильників відвідувачів, популярних на зорі Інтернету.

З моменту релізу PHP, він був використаний в набагато більш складних проектах, ніж очікували його автори. Він зазнав кілька мажорних змін, кожне з яких принесло нові механізми для приборкання цих складних додатків. Сьогодні, в 2016, він є багатим фічами членом сім'ї Змішаної Парадигми Продуктивних Мов (MPDPL) [1], яка включає JavaScript, Python, Ruby і Lua. Якщо ви пробували PHP в ранні 2000-ні, сучасна кодова база PHP може здивувати вас трейтами, замиканнями і генераторами.

Чесноти PHP
PHP має кілька дуже глибоких і, однозначно, вірних особливостей.

Перша, стан. Кожен веб-запит починається з чистого аркуша. Його простір імен та глобальні змінні не ініціалізується, за винятком деяких стандартних глобальних змінних, функцій і класів, що надають примітивну функціональність і життєзабезпечення. Починаючи кожен запит з відомого стану, ми отримуємо свого роду ізоляцію від можливих помилок; якщо запит t стикається з несправністю ЗА і завершується з помилкою, даний баг не робить ніякого впливу на виконання наступного запиту t+1. Насправді, звичайно ж, крім програмної купи, стан додатки знаходиться і в інших місцях, і цілком можливо повністю зіпсувати базу даних, memcache або файлову систему. Але PHP поділяє цю слабкість з усіма середовищами, які дозволяють зберігати стан. У той же час, поділ програмних куп між запитами знижує ціну більшості програмних помилок.

Друга, паралелізм. Індивідуальний запит працює в одному PHP потоці. На перший погляд, це здається дурним обмеженням. Але так як наш додаток виконується в контексті веб-сервера, ми має натуральний джерело паралелізму: веб запити. Асинхронний curl'інг на локалхост (або навіть інший веб-сервер) надає нерозривний (shared-nothing), копіювання/копіювання-з підхід використання паралелізму. На практиці, це безпечніше і стійкіше до помилок, ніж підхід з блокуваннями і подільних станом, який використовується в інших мовах загального призначення.

У висновку, той факт, що PHP програми оперують на рівні запитів, означає, що робочий процес програміста є швидким та ефективним, і залишається швидким після зміни програми. Безліч мов продуктивної розробки претендують на це, але якщо вони не очищають свій стан при кожному запиті, і основний потік подій поділяє програмний рівень стану між запитами, вони майже завжди вимагають деякий час на запуск. Для типового сервера додатків на Python'е, типовий цикл налагодження буде виглядати приблизно як «подумати, відредагувати, перезапустити сервер, відправити кілька тестових запитів». Навіть якщо «перезапустити сервер» займає всього кілька секунд із загальної кількості годин, це забирає великий зріз з 15-30 секунд наших людських мізків на необхідність утримання в голові самої непотрібної частини поточного стану.

Я стверджую, що розробка на PHP в стилі «подумати, відредагувати і перезавантажте сторінку» робить розробників більш продуктивними. В довгих і складних циклах розробки проектів це дає ще більший приріст.

Доводи проти PHP
Якщо все це є правдою, чому ж його так ненавидять? Коли ви приберете всі барвисті гіперболи в бік, що основні скарги про PHP кластері зведуться до наступних проблем:

  1. Сюрпризи при перетвореннях. Майже всі мови в наші дні дозволяють порівняти, наприклад, integer і float з оператором >=; Чорт, навіть C дозволяє. Абсолютно зрозуміло, що тут мається на увазі. Менш очевидно порівняння рядка і числа за допомогою ==, і різні мови робили різний вибір. Вибір PHP в даній ситуації найбільш підступний, що призводить до сюрпризів і неприємних помилок. Приміром, 123 == '123foo' оцінюється як істина (що він там робить?), але 0123 == '0123foo' є брехнею (хмм).

  2. Неузгодженість навколо посилань і семантичних значень. PHP 3 мав чітку семантику передачі аргументів, повернення всього за значенням, створюючи логічну копію даних в запиті. Програміст може вибрати посилальну семантику разом зі знаком & [2]. Це виникло разом з введенням об'єктно-орієнтованих засобів програмування в PHP 4 і 5. Більшість PHP ОО-анотацій були запозичені з Java і Java має семантику, в якій об'єкт передається по посиланню, у той час як примітивні типи передаються за значенням. У результаті, поточний стан семантики PHP полягає в тому, що об'єкти передаються по посиланню (вибираємо Java, замість, скажімо, C++), примітивні типи передаються за значенням (тут Java, C++ і PHP згоден), але стара посилальна семантика і знак & залишилися, час від часу взаємодіючи з новим світом неоднозначними способами.

  3. Філософія обчислень, які ігнорують відмови. PHP намагається дуже, дуже важко зберігати запит запущеним, навіть якщо він вже наробив чого-то зовсім дивного. Так, наприклад, ділення на нуль не кидає виняток, не повертає INF, і не завершує фатально запит. За замовчуванням, він просто попереджає і привласнить значення false. Так як false мовчки розглядається як 0 в числових контекстах, безліч додатків розгортаються і запускаються з недіагностованими поділками на нуль. Конкретно ця проблема була дозволена в PHP 7, але імпульс в дизайні до обробки неоднозначностей, навіть коли вони можуть мати сенс, просочує в тому числі і бібліотеки.

  4. Суперечності в стандартній бібліотеці. Коли PHP був молодим, його аудиторія була найбільш знайома з C, і безліч API використовували дизайн стандартної бібліотеки мови C: шести-символьні імена в нижньому регістрі, відповіді про успішне/неуспішним виконання і повертають реальне значення у викликається параметр «out», і так далі. По мірі розвитку PHP, C-шний стиль поділу простору імен через префікси з _ став більш поширеним: mysql_..., json_..., і так далі. А зовсім недавно, camelCase спосіб іменування методів з Java на класах CamelCase став самим розповсюдженим способом введення нових функціональних можливостей. Так, що в підсумку, іноді ми бачимо приклади коду з перемішаними виразами на кшталт DirectoryIterator($path) разом з if (!($f = fopen($p, 'w+'))… в сбивающей з пантелику логіці.


Щоб не здатися нерефлективным апологетом PHP: все це серйозні проблеми, які дозволяють більш ймовірно створювати дефекти. Вони є явними помилками (unforced errors). Тут немає властивого компромісу між Хорошими Частинами PHP і даними проблемами. Повинна бути реалізована можливість створити PHP, який дозволить дані недоліки, зберігши при цьому всі хороші сторони.

HHVM і Hack
Цей наступник системи PHP зветься Hack [3]

Hack — це така мова програмування, який люди називають «поступова система типів» для PHP. «Система типів» означає, що він дозволяє програмісту складати автоматично перевіряються инварианты про дані, які протікають через код: ця функція бере рядок або число і повертає аркуш Fribbles, як наприклад в Java або C++ або Haskell, або в будь-якому іншому статично типизированном мові, який ви виберете. «Поступова» означає, що деякі частини вашої кодової бази можуть бути статично типізованими, в той час як інші її частини можуть все ще знаходиться в безладному, динамічному PHP. Можливість поєднувати ці підходи дозволяє поступово мігрувати великі кодові бази.

Замість того щоб розлити тут тонни чорнила в описі системи типів Hack і того, як вона працює, просто поиграйтесь з ним. Я буду тут, коли ви повернетесь.

Це акуратна система, і вона дуже амбітна в тому що вона дозволяє вам висловити. І наявність можливості поступової міграції проекту на Hack, у випадках коли він розростається сильніше, ніж ви очікували спочатку, є унікальною перевагою екосистеми PHP. Перевірки типів Hack зберігають робочий процес в стилі «думати, відредагувати, перезавантажте сторінку», тому що вони запускаються в тлі, поступово оновлюючи модель кодової бази, коли він бачить модифікації у файловій системі. Проект Hack надає інтеграції з усіма популярними редакторами і IDE, так що ви зможете побачити зворотний зв'язок про помилки типів вже тоді, коли завершите друкувати код, також як веб-демонстрації.

Давайте розглянемо сукупність реальних ризиків, які створює PHP, у світлі Hack:

  1. Сюрпризи при перетвореннях стають помилками в Hack файлах. Весь клас даних проблем йде геть.
  2. Семантика посилань і значень Hack очищена простим забороною використання посилань старого стилю, так що вони більше не потрібні нової кодової базі. Це робить поведінку семантики аналогічної стилю об'єктів-на засланні, і всього-всього іншого-за-значенням, також як в Java або C#
  3. PHP-шні обчислення, ігнорують відмови є більше властивістю середовища виконання, і їх складніше обробляти аналізатором семантики начебто Hack, щоб впровадити його прямо у ці системи. Тим не менш, на практиці, більшість форм обчислень, які ігнорують відмови, вимагають тих самих сюрпризів при перетвореннях. Приміром, проблеми, які виникають із-за отримання false після ділення на нуль, у підсумку не виникнуть на перетині кордону перевірки типу [4], яка провалиться через спроби перетворити логічне значення на число. Ці межі зустрічаються частіше у кодовій базі Hack. Разом з простою можливістю описувати дані типи, Hack на практиці зменшує «гальмівний шлях» для безлічі некоректних запусків.
  4. На завершення, суперечності в стандартній бібліотеці залишаються. Більшість в Hack сподіваються на те, що зможуть зробити цю проблему менш болючою через обернення її в більш безпечні абстракції.


Hack надає можливість, якої не мають інші популярні члени сім'ї MPDPL: можливість ввести систему типів вже після основної розробки, і тільки частково, у тих частинах системи, де значення переважує ціну.

HHVM
Hack спочатку був розроблений як частина віртуальної машини HipHop, або HHVM, віртуального середовища з відкритим вихідним кодом PHP. HHVM надає іншу важливу опцію для успішного проекту: можливість запустити ваш сайт швидше і більш економно. Facebook доповідає про приріст продуктивності в 11.6 раз на процесорній ефективності над інтерпретатором PHP, а Wikipedia повідомляє про прискорення в 6 разів.

Slack нещодавно переклав свої веб-оточення на HHVM і отримав значні зниження затримок на всіх точках виходу, але нам не вистачає вимірювань в стилі apples-to-apples на процесорні навантаження на момент написання цього тексту. Ми також перебуваємо в процесі переміщення нашої кодової бази на Hack та будемо повідомляти про свій досвід тут.

Дивлячись вперед
Ми почали з очевидного парадоксу про те, що PHP є дуже поганим язиком, який використовується в багатьох успішних проектах. Ми вважаємо, що його репутація як бідного мови, в ізоляції, досить заслужена. Успіх проектів, що використовують його, має багато спільного з основними властивостями середовища PHP, і можливістю прискореної розробки, яка також надає PHP. І переваги від цього оточення (знижене кількість багів через ізоляцію помилок; безпечна паралельність; висока пропускна здатність програмістів) є більш цінними, ніж проблеми, які виникають із-за недоліків мови.

Крім того, на відміну від інших членів сім'ї MPDPL, він надає чіткий шлях для міграції на більш продуктивну, безпечну і обслуговується середовище у вигляді Hack і HHVM. Slack знаходиться на останніх стадіях до переходу на HHVM, і на ранніх етапах переходу на Hack, і ми оптимістично налаштовані, так як вони дозволяють нам виробляти більш якісне програмне забезпечення, більш швидкі терміни.




Примітки (вони теж з блогу розробника):

[1] Це я придумав термін MPDPL. У той час як існує мало генетичних зв'язків між ними, дані мови сильно вплинули один на одного. Дивлячись на минулий синтаксис, можна побачити, що вони мають набагато більше спільного, ніж відмінностей. У всесвіті мов програмування асамблеї MIPS, Haskell, C++, Forth і Erlang, важко заперечувати, що MPDPL утворюють щільний кластер в просторі мовних дизайнів. [назад до тексту]

[2] На жаль, & позначається в одержуваному, а не в зухвалій значенні. Так що коли програміст оголошує про своє бажання отримати параметри за посиланням, це ніяким чином не відображається. Це робить складний для розуміння код і аналіз того, що може змінитися, і значно ускладнює ефективну роботу з PHP. Дивіться Малюнок 2 dl.acm.org/citation.cfm?id=2660199. [назад до тексту]

[3] Так, Hack є практично негуглежным назвою для мови програмування. Іноді використовується Hacklang, коли можлива неоднозначність. Якщо вже Google самі можуть назвати свій популярний мову ще більш негуглежным Go, то чому б і ні? [назад до тексту]

[4] Ці перевірки типів у програмі на Hack також застосовуються під час виконання за замовчуванням, так як вони працюють на основі PHP-шної системи підказок типів. Це збільшує безпеку змішаних кодових баз, де Hack і класичний PHP змішуються один з одним. [назад до тексту]
Джерело: Хабрахабр

0 коментарів

Тільки зареєстровані та авторизовані користувачі можуть залишати коментарі.