Haskell — пока еще единственный язык программирования, в котором есть оператор «фтопку» (>>=)
Планировал начать с описания того, как ошибаются люди, полагающие Haskell бесполезным с практической точки зрения, сферическим языком в вакууме и т.д. Но, боюсь, за меня все уже сделали авторы Real World Haskell. Была идея рассказать о том, насколько красив и могуч этот язык программирования — но подвел тяжелый слог и неумение придумать захватывающий сюжет с неожиданной развязкой. Поэтому отброшу все лишнее и расскажу о своих злоключениях веб-разработки на Haskell.
Действующие лица
Давно хотелось попробовать Haskell для разработки в web. Во-первых — это достаточно близко к моей профессиональной деятельности, во-вторых — это дико интересно) Ну и в итоге получаем способ изучить Haskell и не заснуть за алгоритмами сортировки и поиска факториалов.
Благо, для данного замысла существует куча готовых фреймворков (см. здесь) и необходимых пакетов (впрочем, их существуют неведомые горы для всего).
В сухом остатке, я выбрал Yesod Web Framework. Хотя он достаточно распространен и обладает хорошим функционалом, признаюсь, выбор был совершен методом научного тыка и малообоснован логически.
Помимо этого, хотелось иметь возможность не только поглядеть на результаты своего труда локально, но и похвастаться перед коллегами. Поэтому было задумано опубликовать результаты на Heroku. Для этого потребуется haskell buildpack, например этот (хотя, заранее сообщу, что в моем случае заработал только он))
Yesod
Я постараюсь описать все достаточно подробно и полно — на всякий случай. Итак, для начала потребуется установить Glasgow Haskell Compiler. Любым пакетным менеджером:
emerge -av ghc
Не помешает также cabal:
emerge -av cabal
cabal update
Для того, чтобы не ломать голову над зависимостями, стоит использовать cabal-dev, который позволит устанавливать все необходимые в дальнейшем пакеты в sandbox (похоже на virtualenv).
cabal install cabal-dev
Теперь создадим заготовку для первого приложения. Собственно, за нас все сделает yesod:
yesod init
Указываем название приложения, способ хранения данных (например, в postgresql) и вуаля — получаем директорию с вполне функционирующим веб-приложением. Осталось только установить зависимости с помощью cabal-dev:
cd MyApp
cabal-dev install
Немного медитации на консольный выхлоп — и мы на шаг ближе к реализации задумки. Осталось не забыть указать конфигурацию для бд. Ее можно увидеть в файле config/postgresql.yml — и здесь уже все украдено до нас продумано за нас! В файле присутствуют 4 вида конфигураций (development, testing, staging, production) и конфигурация по умолчанию, от которой все наследуются. Осталось указать имя пользователя бд, пароль и название базы.
Теперь запустим сервер:
yesod devel --dev
Опция --dev сообщает, что необходимо использовать cabal-dev — иначе Yesod будет искать пакеты, установленные в системе.
Все, можно, затаив дыхание, открыть в браузере http://localhost:3000 и насладиться пусть достаточно простым, но уже результатом.
Есть один вопрос, который заставил меня усомниться в своих навыках программиста и просто адекватного человека) Дело в том, что когда пришло время поиграться с проектом, я никак не мог увидеть результат своих стараний (даже если это были изменения в шаблонах!). Оказалось, что для полноценного перезапуска, необходимо выполнить не
cabal-dev build / yesod build
или просто перезапустить development сервер — нужно еще и заново установить приложение
cabal-dev install
Мне кажется это ни разу не очевидным, хотя пока не ясно баг это или фича.
Heroku
Следующий эпизод будет посвящен публикации полученного веб-приложения на Heroku. Вся эта затея возможна благодаря runtime stack под названием Cedar. При использовании этого стека, поддержка различных языков и фреймворков полностью ложится на плечи buildpack'ов, которые подготавливают окружение для запуска приложения.
Heroku поддерживает несколько таких buildpacks, например, для Ruby (ну кто бы сомневался), Node.js, Python и т.д. Помимо этого списка есть знатное количество сторонних buildpacks .
Естесственно, нам нужен таковой для Haskell, который находится без особого труда в указанном выше списке. Причем находится к моему удивлению, т.к. я обнаружил это совсем недавно, а еще некоторое время назад его там не было. На тот момент это сподвигло меня на поиск по github и перебор нескольких репозиториев, среди которых в моих руках заработал этот.
Итак, создаем приложение на heroku:
heroku create my-app --stack=cedar --buildpack https://github.com/<путь к выбранному buildpack>.git
Далее надо инициализировать git репозиторий и добавить в него MyApp. Перед деплоем необходимо внести некоторые изменения, про которые легко можно забыть. Для начала, надо перенести Procfile из директории deploy в корень проекта — в этом файле содержится информация о том, как запустить проект. После стоит поправить production конфигурацию бд и сайта:
- approot из config/settings.yml должен указывать на итоговый url приложения (для загрузки статики, например, «my-app.herokuapp.com»)
- user, password и т.д. из config/postgresql.yml должны содержать реальные данные heroku
По поводу бд — естесственно, для начала необходимо добавить add-on Heroku Postgres. После добавления можно узнать строку подключения командой
heroku pg:info #получаем HEROKU_POSTGRESQL_URL
heroku pg:credentials HEROKU_POSTGRESQL_URL
После комита всех произведенных изменений, указываем удаленный репозиторий heroku:
heroku git:remote -a MyApp
и отправляем изменения на сервер
git push heroku master
Ждем… Перед деплоем с помощью buildpack'а будет подготовлено окружение, будут установлены все зависимости и т.д.
И вот здесь может возникнуть проблема, которая заставляет задуматься. Дело в том, что heroku устанавливает ограничение, которое может не позволить завершить деплой. В попытках выяснить, как и почему, я клонировал репозиторий buildpack'а и осмотрел его. Подопытный напрашивался на эксперименты. Чтобы иметь возможность использовать buildpack локально и, соответственно, сразу видеть результаты всех модификаций, можно воспользоваться плагином heroku push. В этом случае деплой проекта будем производить минуя git:
heroku push -b ~/mybuildpack
После внесения некоторых изменений:
-export PATH=$FIXED_HOME/ghc/bin:$FIXED_HOME/.cabal/bin$PATH
+export PATH=$FIXED_HOME/ghc/bin:$FIXED_HOME/.cabal/bin:$PATH
-cabal install -j5 --disable-library-profiling --disable-executable-profiling --disable-shared
+cabal install -j2 --disable-library-profiling --disable-executable-profiling
к моему удивлению, все заработало и деплой прошел успешно! (бурное обсуждение в комментах поощряется, т.к. я сам доконца не понял, почему это сработало)
Заключение
Yesod — интересный и конкурентноспособный фреймворк, который обладает большим набором возможностей. Любопытно посмотреть на Yesod vs Django. До этого меня останавливал только тот факт, что никто из облачных сервисов вроде GAE, OpenShift и т.д. не собираются иметь дело с Haskell. Ну а раз проблема исчерпана, то можно и даже нужно порадовать себя изучением еще одной интересной штуки. Надеюсь, я не одинок в своих порывах)
В дальнейшем постараюсь рассказать о том, как работает и устроен Yesod. Будет много Шекспира и других плюшек)
P.S.:
Пара презентаций об использовании Haskell в production
mth.io/talks/haskell-in-production
www.shimweasel.com/hs_gbu
Автор: erthalion