Статьи

Переход с PHP на Go: богохульство, бравада или здравый смысл?

Этот пост о переходе с PHP на Go был впервые опубликован в другом месте и переиздан здесь с разрешения автора.


Суслик прогоняет слона

Ранее в этом году я принял возможно плохое деловое решение. Я решил переписать приложение Laravel, включающее Boxzilla в Go .

Хотя не жалею.

Страница платформы Boxzilla

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

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

Stripe и Braintree используются для приема платежей по подписке. Счета обрабатываются с помощью MoneyBird, а некоторые транзакционные электронные письма отправляются с помощью Mailgun .

Хотя Laravel работал достаточно хорошо для этого, некоторые вещи всегда казались мне слишком сложными. И что с выпуском новой «основной» версии каждые несколько месяцев? Было бы неплохо, если бы новые версии содержали значительные улучшения, но во многих случаях мне казалось, что незначительные изменения имен и структуры каталогов меняют.

Зачем идти?

В прошлом году я перевел несколько сервисов на Go, поэтому я не был совершенно новым для этого языка. Как разработчик, продающий продукты на основе WordPress, часть моей работы — работа в древнем техническом стеке, который в основном ориентирован на конечного пользователя.

Если бы я не работал не по найму, я бы просто подал заявку на новую работу, чтобы восполнить недостаток сексуальных технологий. Будучи моим собственным боссом, я обязан сделать так, чтобы моя повседневная работа была интересной, а не просто преследовал более неотложных $$$. Если доход позволяет (и это делает), почему бы не повеселиться?

Писать код на Go — это радость, инструменты потрясающие и не только быстро развивающиеся, но и конечный результат, как правило, тоже безумно быстр. Просто чтение о цели проекта Go продало меня на языке.

Я думаю, что в ближайшие несколько лет мы увидим, как много людей перейдут с динамически типизированных языков, таких как PHP, Python и JavaScript, на Go.

Портирование кодовой базы

Перенос кода на Golang состоял в основном из правильного взаимодействия с базой данных и переноса шаблонов Blade в то, что мы могли бы использовать в Go.

ORM — это одна вещь, которая всегда мешает мне, поэтому я выбрал фиктивный слой доступа к данным и простые SQL-запросы. Meddler использовался, чтобы избавиться от некоторых шаблонов для сканирования результатов запросов в структуры.

Для поддержки иерархических шаблонов и частичных функций я использую grender с открытым исходным кодом , крошечную оболочку стандартного пакета html / template Go. Это позволило мне с относительной легкостью портировать файлы шаблонов Blade на Go, поскольку я мог использовать ту же иерархическую структуру и частичные шаблоны.

Для интеграции с Stripe существует официальный пакет stripe-go . Для Braintree существует неофициальный пакет braintree-go , который некоторое время игнорировался, но в последнее время привлек к себе повышенное внимание. Поскольку в Moneybird еще не было пакета Go для управления счетами, я создал и получил открытый исходный код moneybird-go .

Сравнение яблок и апельсинов

Поскольку Go — это скомпилированный язык с гораздо лучшей стандартной библиотекой, чем PHP, не совсем справедливо сравнивать эти два языка, как я собираюсь. Тем не менее, я думал, что было бы интересно поделиться некоторыми цифрами.

Производительность

wrk использовался для выполнения нескольких простых тестов HTTP для обоих приложений, возвращающих HTML-код для страницы входа в систему.

совпадение Avg. задержка Треб / сек Передача / сек
Laravel 1 3.87ms 261,48 1.27MB
Laravel 100 108.86ms 917,27 6.04MB
Идти 1 325.72μs 7365,48 34.27MB
Идти 100 11.63ms 19967,31 92.91MB
Идти 200 37.68ms 22653,22 105.41MB

К сожалению, приложение Laravel (или сокет PHP-FPM) продолжало падать, как только я увеличил количество одновременных «пользователей» за 100.

NetData предоставила следующие графики, чтобы увидеть, как сервер выдерживал всю эту нагрузку.

Голанг с 100 одновременными соединениями
Перейти с 100 одновременных подключений

Laravel с 100 одновременными подключениями
Laravel с 100 одновременными подключениями

Обратите внимание, что я запускал тест с того же компьютера, на котором работали приложения, так что это сильно влияет на оба графика.

Строки кода

Давайте сравним строки кода в обоих приложениях, включая все зависимости от поставщиков.

find . -name '*.php' | xargs wc -l
156289 total

Версия Laravel состоит из чуть более 156 000 строк кода. Это исключает зависимости разработки, которые, с Laravel, необходимы для запуска тестов и т. Д.

 find . -name '*.go' | xargs wc -l
33624 total

Версия Golang, с другой стороны, состоит из 33 000 строк кода. Это одна пятая часть кода для точно такой же функциональности.

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

 find . -name '*.php' -not -path "./vendor/*" | xargs wc -l
13921 total

И для Голанга.

 find . -name '*.go' -not -path "./vendor/*" | xargs wc -l
6750 total

Результат немного больше, даже если просто смотреть на управляемые строки кода. Тем не менее, это точно такое же приложение с половиной кода.

Тестовое покрытие

Тестирование является первоклассным гражданином в Голанге, и тестовые файлы находятся рядом с реальными исходными файлами.

 license.go
license_test.go
subscription.go
subscription_test.go

Это делает невероятно удобным применение тестовой разработки.

В нашем приложении Laravel у нас были в основном интеграционные тесты, которые проверяли, вернул ли обработчик запросов правильный ответ. Общее тестовое покрытие было довольно низким, в основном из-за жесткой связи, что, в свою очередь, было моей ошибкой Написание того же приложения во второй раз действительно помогает и здесь.

TLDR

Я сделал то, что вы никогда не должны делать: переписал приложение на другом языке, потому что мне так хотелось. Было очень весело, и взамен я получил гораздо меньшее и быстрое приложение.