На этих выходных прошёл ClojureCup — 48 часовый хакатон на Clojure. Это будет относительно длинный пост про то, как он проходил в нашей команде, с техническими деталями и прочим. А в конце поста, куда уж без этого, расскажем совсем немного о нашем проекте.
Рабочее окружение
В участии в хакатоне есть два разных «режима»: участие ради удовольствия и ради победы. В первом случае мы лениво кодим что-то прикольное двое суток; во втором всё немного по-другому, с хардкором и ранним началом подготовки. Мы выбрали второй вариант.
В команде нас было четверо — двое, включая меня и si14, находятся в Петербурге, один — в Тюмени (zloy_alu), еще один — в Мюнхене. Но никаких проблем в коммуникации мы не испытывали — помогала более-менее успешная изоляция задач, отличный сервис Trello и просто божественный FlowDock. Последний, на мой взгляд представляет собой идеал сервиса для внутрикомандного взаимодействия. Судите сами — здесь есть и чат, и обмен файлами, и отдельные ветки обсуждений, и нотификации о разного рода событиях (деплой, push в репозиторий, новые задачи в trello, упоминание в твиттере). Выглядит это все примерно так:
Так как мы явно планировали выиграть, подготовку мы начали заранее. В частности:
- проверили выбранные библиотеки и структуру приложения в целом (подробнее см. ниже про Clony);
- проверили интеграцию со сторонними сервисами вроде NewRelic;
- завели блог и Twitter;
- научились быстро и удобно деплоить (Makefile'ы и Ansible);
- подготовили документацию к JSON API между сервером и web app'ом, что позволило нам писать эти куски более-менее независимо;
- подготовили эскизы интерфейса на бумаге;
- купили домен и выписали SSL-сертификат;
- научились настраивать nginx для нормальной работы с вебсокетами и статическими ресурсами;
- подготовили контакты пула бета-тестеров (тут вышел некоторый фейл — мы отстали от графика и сделали рассылку только в 11 Москвы, поэтому успели получить только один отзыв до конца хакатона).
Технические подробности
А теперь детали о том, что может оказаться полезным для веб-разработчиков на Clojure.
Очень полезным оказался опыт создания небольшого приложения Clony. Это крайне простая штука на Clojure с использованием http-kit (http-сервер и клиент для Clojure) и Compojure (роутер), общающееся со своим фронтендом вебсокетами. В нём используется Stuart Sierra's workflow, благодаря чему разработка становится ощутимо приятнее: мы целиком перезапускали всё наше приложение (или его куски) из nrepl за доли секунды. В ходе хакатона мы сделали несколько улучшений, которые ждут своего backport'а в Clony.
День первый
Мы заранее знали, что будем разворачиваться на виртуальную машину, поэтому научилсь пользоваться Ansible. Благодаря ему мы были онлайн спустя 4 часа с начала соревнований — с полностью развёрнутой production-конфигурацией и тестовым приложением. Это произошло бы раньше, если бы не проблемы с DigitalOcean, предоставлявшим
В первый день мы потратили очень много времени на попытки завести clang — интеграцию Angular.js с ClojureScript. Обилие мелких неприятностей в итоге заставило отказаться от ClojureScript целиком и переключиться на голый JavaScript. ClojureScript гораздо лучше, как язык, но в условиях хакатона сражаться с собственным непониманием его тонкостей было просто некогда.
Пытаясь сделать все как можно более правильно, мы решили добавить в проект библиотеку для SQL-миграций. Интересно было обнаружить, что весьма популярная библиотека для миграций Lobos не работает вовсе. В результате мы потеряли около часа на поиск и разбирательство с новой; остановились на Ragtime.
В итоге в конце первого дня у нас была красивая главная страница и полурабочий список репозиториев (небольшое описание нашего проекта чуть ниже). В промежутке 22:00–03:00 команда разбрелась спать (к этому моменту никто не спал с 4 утра) и снова собрались мы около 8 утра в воскресенье.
День второй
В воскресенье дела пошли лучше, но и проблем было достаточно много:
- пришлось переделать небольшой кусок OAuth-авторизации;
- в какой-то момент нас забанил GitHub по лимиту запросов API, что было крайне неприятно, и нам пришлось количество отправляемых запросов;
- для генерации картинок мы сначала пытались использовать что-то на чистой Java, но в итоге взяли биндинг к ImageMagick. Их есть два: один работает через sh и pipes, другой через JNI. Первый тормозит (30+мс на картинку), на завести второй так и не удалось;
- и с медленной генерацией картинок, и с количеством запросов к GitHub нас выручил core.cache — прекрасная «core» библиотека Clojure;
- мы приняли рискованное решение взять core.async для работы с событиями на сервере. В итоге это оказалось неплохим решением: первая рабочая версия кода с его использованием родилась за полтора часа и проблем с ним практически не было, несмотря на то, что никто в команде до этого его не использовал. С помощью core.async мы сделали возможность из любого места кода удобно писать в вебсокет конкретного пользователя и сложную логику перезапуска сканирования репозиториев в случае перегрузки сервера: мы обрабатываем очередь запросов на сканирование, отбрасывая всё, что переполняет очередь, и в случае отсутствия заданий в основной очереди выбираем из базы то, что выбросили при перегрузке. Код получился очень компактным и вроде бы работает;
- баги на клиенте, часть из которых, увы, мы не успели исправить до конца хакатона.
В целом, второй день прошёл более чем продуктивно. Мы пытались ориентироваться на первое впечатление, поэтому уделили внимание мелочам: редирект на наш собственный домен, красивый «How to Use», понятный текст на главной, приятный дизайн, плашки с «извините, у вас нет TODO в репозитории, вот форма багрепорта, если это не так». Конечно, для ускорения разработки мы использовали Bootstrap, но попытались сделать все максимально красиво и «недефолтно». Насколько это всё поможет нам получить лучшие оценки от судей, мы узнаем в пятницу.
Самое интересное — о чем это все?
Будет странным совсем ничего не сказать о нашем проекте.
Нам кажется, человечество ещё не придумало идеальный багтрекер. Впрочем… Зачем нам багтрекер вообще? Суть нашего проекта — убрать отдельный багтрекер из вашей жизни. И мы постарались и будем стараться дальше для того, чтобы он мог выглядеть так:
def somefun():
# TODO: si14, please fix this before release
return true
А остальное сделаем мы — вышлем пользователю нотификацию о том, что вы создали для него задачу, отобразим ее в нашем интерфейсе, а также будем следить за вашими коммитами и сканировать код на предмет новых TODO, FIXME и NOTE. Кроме того, вы можете сгенировать красивую картинку для своего репозитория на GitHub с указанием того, сколько TODO в вашем коде и ссылкой на информацию об этом. Наш проект CodeNotes пока не обладает всем желаемым функционалом (плюс там пока есть немного достаточно досадных багов, что уж скрывать), но когда голосование закончится, мы тут же продолжим улучшать его и делать из него лучший багтрекер для небольших проектов.
А пока, кстати, вы можете проголосовать за нас и высказаться в комментариях о том, что вы думаете об идее, о хакатонах и в целом о веб-программировании на Clojure.
Автор: alwxndr