Веб-разработка на Go
Рассматривая разные языки программирования в недавнем времени я наткнулся на публикации различных авторов о веб-разработке на языке Go от компании Google. Язык является относительно молодым, так как выход первой версии состоялся еще в 2007 году. Однако популярность данный язык обрел спустя около 10 лет. На сегодняшний день не многие компании, которые занимаются веб-разработкой готовы использовать Go в своих продуктах.
Введение
Раньше моих базовых знаний HTML, CSS и JavaScript было достаточно для моих скромных нужд в сайтостроении. Большинство приложений, которые я когда-либо создавал, были сделаны с использованием Rails после изучения Ruby. В течение последнего времени я сосредоточился на разработке разных проектов на Ruby для улучшения навыков как самого программирования, так и навыков в сфере backend-рабработки. Сейчас, изучив Ruby и изнакомившись с Python по материалам статей и по рынку заказов на фрилансе, я бы рекомендовал Python или Ruby в качестве среды веб-приложения. Может быть есть и другие подобные языки, но с моей точки зрения, в мире доминируют Python и Ruby. Большую часть времени главной задачей веб-приложения было конструирование веб-страниц с помощью компоновки конечного HTML на стороне сервера. Как Python, так и Ruby очень хорошо подходят для извлечения данных из базы данных и превращению их в кучу HTML-кода с помощью шаблонов. Существует множество фреймворков/инструментов на выбор, например, Rails, Django, Sinatra, Flask и т.д. и т.п. И хотя эти языки имеют определенные существенные ограничения, такие как Global Interpreter Lock, легкость, с которой они решают проблему генерации HTML, намного ценнее компромиссов, на которые приходится идти.
Global Interpreter Lock (GIL)
Global Interpreter Lock (GIL) залуживает отдельного упоминания. Безусловно, это самое большое ограничение любого решения на Python или Ruby, но это очень скользкая тема, люди чаще предпочитают делать вид, что проблемы нет. А если уж речь об этом зашла, эмоции обычно бьют через край, в сообществах Ruby и Python идут бесконечные обсуждения на тему GIL. Для тех, кто незнаком с этой проблемой — GIL позволяет выполнятся только одной вещи за раз. Когда вы создаете потоки и они ”выглядят” как параллельно выполняющиеся, на самом деле интерпретатор все еще выполняет инструкции последовательно. Это означает, что один процесс может использовать только один CPU. Существуют альтернативные реализации, например, основанные на JVM, но они нечасто применяются. Я точно не знаю почему, возможно они не полностью совместимы или, вероятно, не поддерживают корректно C-расширения, и у них при этом все еще может быть GIL. Не уверен, но насколько я могу судить, обычно все-таки используется реализация на C. Чтобы сделать интерпретатор без GIL, придется его полностью переписать, а это уже может изменить поведение языка (в моем наивном понимании), и поэтому мне кажется, что GIL останется. Веб-приложения любого значительного масштаба обязательно требуют возможность обслуживания запросов параллельно, используя возможности каждого имеющегося у машины CPU. Пока единственным возможным решением остается запуск нескольких экземпляров приложения как отдельных процессов. Обычно это делается с помощью дополнительного программного обеспечения, такого как Unicorn/Gunicorn, при этом каждый процесс слушает свой собственный порт и запускается позади какого-то балансировщика соединения, типа Nginx и/или Haproxy. Альтернативно это может быть сделано через Apache и его модули (такие как mod_python или mod_wsgi), в любом случае это сложно. Такие приложения обычно полагаюся на сервер базы данных в качестве арбитра для любых, чувствительных к конкурентности, задач. При реализации кэширования, чтобы не хранить множество копий одного и того же на одном и том же сервере, требуется хранилище с разделяемой памятью, типа Memcached или Redis, а обычно оба [1]. Также такие приложения не могут делать фоновую обработку, для этого существует отдельный набор инструментов, такой как Resque. И потом все эти компоненты требуют мониторинга, чтобы быть уверенным, что все это работает. Логи должны быть консолидированными, и для них есть свои дополнительные инструменты. Учитывая неизбежную сложность этой настройки, также требуется наличие менеджера конфигурации, такого как Chef или Puppet. И тем не менее, эти наборы, как правило, не способны поддерживать большое количество долговременных соединений — проблема известная как C10K [1]. В итоге простое веб-приложение с базой данных требует целую кучу составных частей, прежде чем оно сможет обслуживать страницу «Hello World!». И почти все это из-за GIL.
Появление одностраничных приложений
Все дальше и дальше в прошлое уходит генерация HTML на сервере. Последняя тенденция заключается в построении пользовательского интерфейса и рендеринге полностью на стороне клиента, с помощью JavaScript. Приложения, чей пользовательский интерфейс полностью управляется JS, иногда называют одностраничным приложением и, на мой взгляд, за ними будущее, нравится нам это или нет. В таких приложениях сервер только обслуживает данные, обычно в виде JSON, не создавая HTML-кода. В этом случае та огромная сложность, введенная в первую очередь для возможности использования популярного скриптового языка (для создания веб-прилолжения), оказывается ненужной. Особенно учитывая, что Python или Ruby приносят мало выгоды, когда весь вывод — это JSON [2].
Взгляд на Golang
Go постепенно подрывает устоявшийся мир веб-приложений. Он нативно поддерживает параллельное выполнение, что устраняет потребность почти во всех компонентах, обычно используемых для работы с ограничениями GIL. Программы на Go представляют собой бинарники, которые нативно запускаются, так что не требуется ничего языкоспецифического устанавливать на сервер. Исчезает проблема обеспечения правильной версии среды исполнения, требуемой приложением; отдельной среды исполнения нет — она встроена в бинарник. Программы на Go могут легко и элегантно запускать задачи в фоне, поэтому нет нужды в инструментах типа Resque. Эти программы запускаются как единственный процесс, так что кэширование становится тривиальным, а значит, Memcached или Redis не нужны. Go может управлять неограниченным количеством параллельных соединений, нивелируя надобность в фронтэндной защите, такой как Nginx [3]. С Go высокая многослойная башня из Python, Ruby, Bundler, Virtualenv, Unicorn, WSGI, Resque, Memcached, Redis, и т.д. , и т.п. уменьшается до всего лишь одного бинарника [4]. Единственный сторонний компонент, который обычно все еще нужен, — это база данных (я бы посоветовал PostgreSQL). Тут важно отметить, что все эти инструменты по прежнему можно использовать, но с Go можно обойтись и без них. Время запуска такой Go-программы будет, скорее всего, на порядок превосходить любое приложение на Python/Ruby, потребует меньше памяти и строк кода.
Популярный фреймворк
Одним из вопросов, который возникает перед разработчиков, когда он начитает итересоваться написанием веб-приложений на Go - есть ли популярный фреймверк? Краткий ответ таков: фреймворк является необязательным и не рекомендуется. Существует множество проектов, претендующих на роль отличного фреймворка, но я считаю, что лучше обойтись без них. Это не мое личное мнение, я нахожу это мнение довольно распространенным в сообществе Go. Надо понимать, зачем вообще были созданы фреймворки. В мире Python/Ruby так случилось потому, что эти языки не были изначально спроектированы для обслуживания веб-страниц, и для решения этой задачи необходимо было множество внешних компонентов. То же самое можно сказать и про Java, который, как и Python, и Ruby, стары как веб, каким мы его знаем, или даже немного старше. Насколько я помню, ранние версии Python "из коробки" не предоставляли ничего для работы с базой данных, не было шаблонов, поддержка HTTP была запутанной, работа с сетью — нетривиальной, даже шифрование тогда было незаконным и в общем, много чего еще отсутствовало. Фреймворк обеспечивал все эти необходимые кусочки и устанавливал характерные для языка правила разработки для всех распространенных вариантов веб-приложений. Go, с другой стороны, создавался людьми, которые уже имели опыт и разбирались в веб-разработке. Он включает в себя практически все необходимое. Один-два внешних пакета могут понадобиться для решения некоторых конкретных задач, типа OAuth, но ни в коем случае эта пара пакетов не является "фреймворком". Если все вышеприведенное касаемо фреймворков звучит не достаточно убедительно, полезно рассмотреть кривую обучения для фреймворков и риски. Мне понадобилось 7 месяцев, чтобы наладить отношения с Rails. Фреймворки могут стать заброшенными и устаревшими, а переносить приложение на новый фреймворк тяжело, а иногда и невозможно. Учитывая, как быстро все меняется в информационных технологиях, фреймворк уж точно не следует выбирать легкомысленно. Я хотел бы особо выделить инструменты и фреймворки, которые пытаются имитировать идиомы, общие для Python, Ruby или сред JavaScript. Все, что выглядит, или ощущается, или претендует на роль «Rails for Go», включая такие техники, как инъекции, динамическая публикация методов и т.п., которые сильно зависят от рефлексии, не вписывается в идеологию Go, поэтому лучше от такого держаться подальше. Несомненно, фреймворки делают некоторые вещи проще, особенно в типичном мире CRUD-приложений для бизнеса, где приложения имеют множество страниц с большим количеством полей, манипулируют данными в сложных и постоянно меняющихся схемах баз данных. Не уверен, что в такой среде Go — хороший выбор, особенно если производительность и масштабируемость не в приоритете. Другая проблема, общая для фреймворков, это то, что они абстрагируют низкоуровневые механизмы от разработчика так, что со временем они становятся настолько загадочными, что буквально невозможно понять, что у них там на самом деле происходит. То, что начинается с лексического псевдонима для одной строки JavaScript становится слоем в слоях транспайлеров, минимайзеров, поверх хелперов, скрытых где-то в подзависимостях. Однажды что-то ломается, и невозможно понять, где искать проблему. Приятно, когда точно знаешь, что происходит, и Go в этом очень хорош.
Работа с базами данных через Object-Relational Mapping
Аналогично фреймворкам, Object-Relational Mapping (ORM) в Go не сильно распространены. Уже имеются некоторые пакеты, которые реализовывают ORM для Go, однако они еще не имеюттако гипкости как к примеру ORM в Rails. В Rails, доступная гипкость ORM позволяет с легкостью обрабатывать данные, полученные из базы данных в то время как в Go инога приходиться писать дополнительный код на обработку данных. Иногда приходиться писать просто SQL запросы, так как ORM не всегда поддерживает то, что разработчик хочет получить в итоге.
Опыт разработки
Из личного опыта разработки следует отметить быстроту языка. Операции работы с данными выполнятся очень быстро. Сам язык является очень спецефическим по причине то, что многие принципы построения архитектуры языка ООП не соблюдаются. В языке отсутствуют классы. Отсутствие наследования и прочего заменяется функциями. Следует отметить что Go построен исключительно на функциях. Объявление переменных напоминает синтаксис языка Java. Библиотеки реализованы несколько иначе. В Go библиотеки называются пакетами и представляют собой определенный набор функций. Взаимодействие с функциями других пакетов осуществяется путем импорта необходимого пакета в другой пакет, который вызывает объявленные функции. Большое сообщество сторонников языка Go и его популярность обеспечивают стремительное появление разнообразных пакетов, которые реализуют разные решения могих задач. Очень многие пакеты имеют бесплатную лицензию и находятся на общедоступных ресурсах. Двумя самыми популярными ресурсами для пакетов Go являются Github и Gitlab.
Заключение
На мой взгляд, Go является достаточно интересным языком программирования, который может использоваться в разных сферах IT-индустрии, как в веб-разработке так и справляться с задачами системного программирования. А популярность его и спрос на специалистов, которые программируют на данном языке программирования, всегда стимул для развития языка и появления множества разных производительных пакетов, которые улушат процесс разработки на Golang.
Список источников
- Разработка веб-приложения на Golang [Электронный ресурс]. — Режим доступа:https://habr.com/post/260539/. — Заглавие с экрана.
- Веб-разработка на Go [Электронный ресурс]. — Режим доступа:https://habr.com/post/122095/. — Заглавие с экрана.
- DevConf 2014: Пишем функциональное, надежное и быстрое веб-приложение на Go [Электронный ресурс]. — Режим доступа:https://habr.com/company/devconf/blog/223755/. — Заглавие с экрана.
- Современная веб-разработка: выбери себе приключение [Электронный ресурс]. — Режим доступа:https://habr.com/company/avito/blog/426851/. — Заглавие с экрана.