Оффтоп Taras Polishchuk
1 539

Кодинг в «Восточном экспрессе»: как мы выиграли международный хакатон в поезде

Какую идею реализовали разработчики онлайн-сервиса для путешественников TripMyDream, чтобы стать лучшими среди 40 участников.

В закладки

В ноябре 2017 года чешский офис онлайн-турагентства Kiwi.com при поддержке железнодорожного оператора RegioJet организовал международный хакатон на тему путешествий. Главная особенность конкурса в том, что он проходил в поезде. Команды проехали по маршруту Прага — Кошице — Прага, разрабатывая собственные сервисы для путешественников прямо на ходу.

Мы с коллегами из TripMyDream создали проект Fly2event и заняли первое место. Расскажу подробнее о самой идее, процессе разработки и сложностях программирования в поезде.

Кто ездит кодить в поездах

Наша команда состояла из четырёх человек, все — сотрудники TripMyDream. Кроме меня, в команде был ещё один разработчик ПО Павел Онысько, специалист по обработке данных Денис Пономаренко, за UI и UX отвечал Андрей Куроедов.

Тот факт, что мы давно сработались как команда, сыграл нам на руку. Некоторые пришли без партнёров и объединялись уже на месте. В общей сложности на хакатоне было около 40 участников, которые образовали 12 команд.

Хакатон стартовал на главном железнодорожном вокзале Праги. В 20:00 участники собрались в бизнес-лаунж, организаторы произнесли приветствие, после чего команды презентовали свои идеи.

Мы представили идею сервиса, который анализирует профиль пользователя в Facebook, персонально рекомендует интересные мероприятия, а также подбирает авиабилеты и отели.

В презентации задекларировали, что работаем с чистого листа: у нас был только логотип, разработанный для самой презентации, и идея. Всё остальное делали в дороге.

Приведу и другие примеры. Одна команда взялась за создание AR-сервиса, который идентифицирует географические объекты. Например, вы наводите камеру на гору или озеро, и сервис показывает название. Ещё один интересный проект — сервис аренды парковочных мест между частными лицами (что-то вроде «Uber для парковок»).

После презентаций мы отправились на посадку. Для участников и организаторов было выделено два вагона в обычном поезде Прага — Кошице.

Каждый вагон разделили примерно пополам: в одной половине — купе с удобными креслами, в другой — опенспейс со столиками и стульями. Конечно, хотелось занять купе, чтобы уединиться и сосредоточиться на разработке. Но мы перед посадкой общались с менторами, а когда пришли, в вагоне оставался один свободный столик в опенспейсе. Позже выяснилось, что это даже хорошо.

Функциональность и технологии Fly2event

Функции сервиса Fly2event — персонализированный подбор интересных мероприятий и организация путешествия: бронирование авиабилетов и отеля.

Пользователь авторизируется через Facebook и сервис подбирает, например, музыкальные мероприятия: концерты, фестивали. В топе — те группы, которые наиболее релевантны предпочтениям пользователя.

Также Fly2event поможет организовать поездку на футбольный матч. В топе — игры любимых команд пользователя.

Ещё одна функция — подбор культурных мероприятий: кинофестивалей, выставок, недель моды.

Также мы предусмотрели рекомендации без авторизации, а ещё — рекомендации для тех, у кого профиль заполнен недостаточно. Для этого применили нейронную сеть, которая на основании известных о пользователе данных и действий других пользователей в системе строила рекомендации по мероприятиям.

Для создания сервиса мы использовали комбинацию языков программирования: бэкенд мы разрабатывали на языке Hacklang, для сбора данных и построения нейронной сети использовали PHP и FANN. Фронтенд разработан на чистом JavaScript. Дизайн рисовали в Sketch.

Все данные о мероприятиях мы парсили прямо по ходу хакатона, собрали в базе 15 тысяч ивентов. Цены на отели и авиаперелеты тоже собирали в процессе: с сайтов двух самых популярных лоукостеров Европы и с крупного агрегатора цен на гостиницы.

Изначально внедрили возможность автовыбора аэропортов вылета по geo ip, но в процессе финализации прототипа ограничили вылеты только аэропортами Польши. Отели искали только в тех городах, где проводится мероприятие.

У нас было примерно 16 часов на разработку в непростых условиях, и за это время мы получили примерно 450 тысяч готовых туров на мероприятия. Добиться таких результатов помог опыт работы с динамическим пакетированием и другими продуктами TripMyDream.

Как проходил хакатон

Мы отправились из Праги в 21:44. Самым большим испытанием на старте оказалось то, что пришлось собирать данные в условиях нестабильного интернета. Также нужно было спланировать работу с учётом того, что необходимые данные будут использоваться не сразу, а по мере поступления. У нас получилось правильно расставить приоритеты, разработать чёткий план и избежать ситуации, когда сроки горят, а ещё ничего не готово.

В Кошице поезд прибыл в 6:14 утра. По приезде все команды отложили ноутбуки и отправились завтракать на вокзале. Снова состоялись короткие презентации: каждая команда рассказала о своем прогрессе.

Затем было около часа свободного времени. Заниматься разработкой в этот период было запрещено. В 8:00 мы отправились обратно и продолжили разработку.

Сложности и вызовы кодинг-марафона

В рабочем процессе важную роль играло качество интернета. В поезде организаторы обеспечили интернет через Wi-Fi, но он работал нестабильно. Мы перед началом хакатона купили SIM-карту местного оператора, время от времени переключались на мобильный интернет, но он тоже был не идеален.

Сложилось впечатление, что покрытие в малонаселённых районах (в дороге) на Украине гораздо более качественное, чем в Чехии. Мы старались приспосабливаться к тому интернету, который был доступен через Wi-Fi.

Большинство операций требовало стабильной связи, поэтому нам приходилось постоянно быть начеку: следить за качеством соединения, переключаться между Wi-Fi-сетями и мобильным интернетом, перезапускать сервисы парсинга, проверять возможные потери данных.

Только на середине обратной дороги мы закончили процесс парсинга. Оставалось не так много времени, чтобы протестировать разработанный функционал на реальных данных.

Ещё одно испытание ждало нас в конце марафона. Примерно за час до прибытия в Прагу стало понятно, что придётся выбирать: либо мы добавляем все запланированные фишки, либо фокусируемся на качественной работе ключевой технологии, её тестировании и отладке.

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

Как это — кодить в поезде

Писать код в поезде — то ещё испытание, и не все команды его выдержали. Некоторые участники уснули прямо на рабочих местах уже через четыре часа после старта. Только две команды не спали на протяжении всего хакатона, и мы — одна из них.

Самыми сложными были пару часов перед Кошице и первые два часа обратной дороги. В эти периоды в головах оставалась только одна мысль: «Как бы не уснуть». Большинство действий выполнялось исключительно на автопилоте.

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

Оставаться на ногах помогали энергетические напитки и кофе. Вообще стоит отдельно выделить кейтеринг. Организаторы не давали участникам проголодаться, постоянно были в наличии напитки (энергетики, пиво, кофе) и снэки. Угощали пиццей, сэндвичами. Также был ужин из коробки, но он оказался холодным и не слишком съедобным.

К счастью, самый сложный период пришёлся на середину хакатона, и в запасе оставалось ещё достаточно времени после того, как на улице и в наших головах окончательно прояснилось.

Обратная дорога пришлась на светлое время суток, поэтому воспринималась легче, не взирая на усталость. За окном большую часть пути красовались словацкие Татры.

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

Итоги хакатона

В 16:12 мы вернулись в Прагу, сделали короткий перерыв, после чего команды презентовали готовые проекты. Из-за дефицита времени и нестабильного интернета не все сумели реализовать задуманное.

И чем интереснее была идея, тем ниже оказался процент её реализации. Но мы создали именно то, что задекларировали вначале. Это был один из плюсов, который выделили менторы, хотя поначалу некоторые были настроены скептически.

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

На итоговой презентации мы были уверены в своем продукте, но небольшое волнение всё равно оставалось. Сложно предсказать ход мыслей менторов, которым предстояло судить проекты.

Каждую работу оценивали по шкале от нуля до пяти по четырём критериям: инновационность, технологии, дизайн и презентация. Интрига сохранялась до последнего. Третье место занял голосовой тревел-ассистент Hackiwi, второе — проект PickmeUp, поиск попутчиков для авиапутешествий. И, наконец, на сцену пригласили команду Fly2event, мы получили первое место в общем зачёте.

В качестве приза мы получили сертификаты на покупку авиабилетов. Нашей команде достался сертификат на €2500, PickmeUp получили сертификат на €1000, Hackiwi — на €500.

Но главный приз — это, конечно, гордость за команду. Код Fly2event мы планируем отладить и запустить как отдельный сервис. Сейчас сервис находится в открытом доступе в виде рабочего прототипа без обновления данных.

Материал опубликован пользователем. Нажмите кнопку «Написать», чтобы поделиться мнением или рассказать о своём проекте.

Написать
{ "author_name": "Taras Polishchuk", "author_type": "self", "tags": [], "comments": 1, "likes": 19, "favorites": 1, "is_advertisement": false, "subsite_label": "flood", "id": 30843, "is_wide": false }
00
дни
00
часы
00
мин
00
сек
(function(){ var banner = document.querySelector('.teaserSberbank'); var isAdsDisabled = document.querySelector('noad'); if (!isAdsDisabled){ var countdownTimer = null; var timerItem = document.querySelectorAll('[data-sber-timer]'); var seconds = parseInt('15388' + '59599') - now(); function now(){ return Math.round(new Date().getTime()/1000.0); } function timer() { var days = Math.floor(seconds / 24 / 60 / 60); var hoursLeft = Math.floor((seconds) - (days * 86400)); var hours = Math.floor(hoursLeft / 3600); var minutesLeft = Math.floor((hoursLeft) - (hours * 3600)); var minutes = Math.floor(minutesLeft / 60); var remainingSeconds = seconds % 60; if (days < 10) days = '0' + days; if (hours < 10) hours = '0' + hours; if (minutes < 10) minutes = '0' + minutes; if (remainingSeconds < 10) remainingSeconds = '0' + remainingSeconds; if (seconds <= 0) { clearInterval(countdownTimer); } else { timerItem[0].textContent = days; timerItem[1].textContent = hours; timerItem[2].textContent = minutes; timerItem[3].textContent = remainingSeconds; seconds -= 1; } } timer(); countdownTimer = setInterval(timer, 1000); } else { banner.style.display = 'none'; } })();
{ "id": 30843, "author_id": 127658, "diff_limit": 1000, "urls": {"diff":"\/comments\/30843\/get","add":"\/comments\/30843\/add","edit":"\/comments\/edit","remove":"\/admin\/comments\/remove","pin":"\/admin\/comments\/pin","get4edit":"\/comments\/get4edit","complain":"\/comments\/complain","load_more":"\/comments\/loading\/30843"}, "attach_limit": 2, "max_comment_text_length": 5000, "subsite_id": 199791 }

1 комментарий 1 комм.

Популярные

По порядку

Комментарий удален

Комментарий удален

Комментарий удален

Комментарий удален

–1

Странная история - на главной показывает 3 комментария, не загрузился - ни один.
А вообще хотел написать, что история напомнила давний афоризм: люди сначала гоняются за деньгами, тратя здоровье, потом гоняются за здоровьем, тратя деньги...

Ответить
0

Прямой эфир

[ { "id": 1, "label": "100%×150_Branding_desktop", "provider": "adfox", "adaptive": [ "desktop" ], "adfox_method": "createAdaptive", "auto_reload": true, "adfox": { "ownerId": 228129, "params": { "pp": "g", "ps": "bugf", "p2": "ezfl" } } }, { "id": 2, "label": "1200х400", "provider": "adfox", "adaptive": [ "phone" ], "auto_reload": true, "adfox": { "ownerId": 228129, "params": { "pp": "g", "ps": "bugf", "p2": "ezfn" } } }, { "id": 3, "label": "240х200 _ТГБ_desktop", "provider": "adfox", "adaptive": [ "desktop" ], "adfox": { "ownerId": 228129, "params": { "pp": "g", "ps": "bugf", "p2": "fizc" } } }, { "id": 4, "label": "240х200_mobile", "provider": "adfox", "adaptive": [ "phone" ], "adfox": { "ownerId": 228129, "params": { "pp": "g", "ps": "bugf", "p2": "flbq" } } }, { "id": 5, "label": "300x500_desktop", "provider": "adfox", "adaptive": [ "desktop" ], "adfox": { "ownerId": 228129, "params": { "pp": "g", "ps": "bugf", "p2": "ezfk" } } }, { "id": 6, "label": "1180х250_Interpool_баннер над комментариями_Desktop", "provider": "adfox", "adaptive": [ "desktop" ], "adfox": { "ownerId": 228129, "params": { "pp": "h", "ps": "bugf", "p2": "ffyh" } } }, { "id": 7, "label": "Article Footer 100%_desktop_mobile", "provider": "adfox", "adaptive": [ "desktop", "tablet", "phone" ], "adfox": { "ownerId": 228129, "params": { "pp": "g", "ps": "bugf", "p2": "fjxb" } } }, { "id": 8, "label": "Fullscreen Desktop", "provider": "adfox", "adaptive": [ "desktop", "tablet" ], "auto_reload": true, "adfox": { "ownerId": 228129, "params": { "pp": "g", "ps": "bugf", "p2": "fjoh" } } }, { "id": 9, "label": "Fullscreen Mobile", "provider": "adfox", "adaptive": [ "phone" ], "auto_reload": true, "adfox": { "ownerId": 228129, "params": { "pp": "g", "ps": "bugf", "p2": "fjog" } } }, { "id": 10, "disable": true, "label": "Native Partner Desktop", "provider": "adfox", "adaptive": [ "desktop", "tablet" ], "adfox": { "ownerId": 228129, "params": { "pp": "g", "ps": "clmf", "p2": "fmyb" } } }, { "id": 11, "disable": true, "label": "Native Partner Mobile", "provider": "adfox", "adaptive": [ "phone" ], "adfox": { "ownerId": 228129, "params": { "pp": "g", "ps": "clmf", "p2": "fmyc" } } }, { "id": 12, "label": "Кнопка в шапке", "provider": "adfox", "adaptive": [ "desktop" ], "adfox": { "ownerId": 228129, "params": { "p1": "bscsh", "p2": "fdhx" } } }, { "id": 13, "label": "DM InPage Video PartnerCode", "provider": "adfox", "adaptive": [ "desktop", "tablet", "phone" ], "adfox_method": "createAdaptive", "adfox": { "ownerId": 228129, "params": { "pp": "h", "ps": "bugf", "p2": "flvn" } } }, { "id": 14, "label": "Yandex context video banner", "provider": "yandex", "yandex": { "block_id": "VI-223676-0", "render_to": "inpage_VI-223676-0-1104503429", "adfox_url": "//ads.adfox.ru/228129/getCode?pp=h&ps=bugf&p2=fpjw&puid1=&puid2=&puid3=&puid4=&puid8=&puid9=&puid10=&puid21=&puid22=&puid31=&puid32=&puid33=&fmt=1&dl={REFERER}&pr=" } }, { "id": 15, "label": "Плашка на главной", "provider": "adfox", "adaptive": [ "desktop", "tablet", "phone" ], "adfox": { "ownerId": 228129, "params": { "p1": "byudx", "p2": "ftjf" } } }, { "id": 16, "label": "Кнопка в шапке мобайл", "provider": "adfox", "adaptive": [ "tablet", "phone" ], "adfox": { "ownerId": 228129, "params": { "p1": "byzqf", "p2": "ftwx" } } }, { "id": 17, "label": "Stratum Desktop", "provider": "adfox", "adaptive": [ "desktop" ], "auto_reload": true, "adfox": { "ownerId": 228129, "params": { "pp": "g", "ps": "bugf", "p2": "fzvb" } } }, { "id": 18, "label": "Stratum Mobile", "provider": "adfox", "adaptive": [ "tablet", "phone" ], "auto_reload": true, "adfox": { "ownerId": 228129, "params": { "pp": "g", "ps": "bugf", "p2": "fzvc" } } }, { "id": 19, "label": "Тизер на главной", "provider": "adfox", "adaptive": [ "desktop", "tablet", "phone" ], "auto_reload": true, "adfox": { "ownerId": 228129, "params": { "p1": "cbltd", "p2": "gazs" } } } ]
Приложение-плацебо скачали
больше миллиона раз
Подписаться на push-уведомления