Меня зовут Дмитрий. И я хочу рассказать о том, как наша команда вышла в финал хакатона Urban Tech Challenge по треку Big Data. Сразу скажу, что это не первый хакатон, в котором я участвовал, и не первый, в котором занимаю призовые места. В связи с этим, в своем рассказе я хочу озвучить некоторые общие наблюдения и выводы, касающиеся индустрии хакатонов в целом, и дать свою точку зрения в противовес негативным отзывам, которые появились в сети сразу после окончания Urban Tech Challenge (например этот).
Итак, сначала некоторые общие наблюдения.
1. Удивляет, что довольно многие люди наивно думают, что хакатон — это что-то вроде спортивного соревнования, где побеждают лучшие кодеры. Это не так. Я не рассматриваю случаи, когда организаторы хакатона сами не знают, чего они хотят (видел и такое). Но, как правило, компания, которая устраивает хакатон, преследует свои цели. Их список может быть разным: это может быть техническое решение каких-то проблем, поиск новых идей и людей и т.д. Эти цели часто определяют формат мероприятия, его сроки, онлайн/оффлайн, то, как будут сформулированы задачи (и будут ли они вообще сформулированы), будет ли на хакатоне code review и т.д. И команды, и то, что они сделали, оцениваются именно с этой точки зрения. И побеждают те команды, которые лучше всего попадают в точку, нужную компании, причем многие попадают в эту точку совершенно неосознанно и случайно, думая, что они действительно участвуют в спортивном состязании. Мои наблюдения показывают, что для мотивации участников организаторам следует создавать хотя бы видимость спортивной обстановки и равных условий, в противном случае они получают волну негатива, как в указанном выше отзыве. Но мы отклонились.
2. Отсюда следующий вывод. Организаторы заинтересованы в том, чтобы участники приходили на хакатон со своими наработками, иногда для этого даже специально устраивается заочный онлайн этап. Это позволяет получить более сильные решения на выходе. Понятие «свои наработки» — очень относительное, любой опытный прогер может в первый же коммит накопипастить тысячи строк кода из своих старых проектов. И будет ли это заранее подготовленной наработкой? Но в любом случае действует правило, которое я выразил в виде известного мема:
Для победы у вас должно что-то быть, какое-то конкурентое преимущество: похожий проект, который Вы делали в прошлом, знания и опыт в какой-то специфической теме или уже готовая наработка, сделанная до начала хакатона. Да, это не спортивно. Да, это может не окупить затраченных усилий (тут уж каждый сам решает, стоит ли кодить 3 недели по ночам за приз в 100 тысяч, поделенный на всю команду, да еще и с риском его не получить). Но, зачастую, это единственный шанс вырваться вперед.
3. Подбор команды. Как я заметил по чатам хакатонов, многие подходят к этому вопросу довольно легкомысленно (хотя, — это самое важное решение, которое определит Ваш результат на хакатоне). По многим сферам деятельности (и по спорту, и по хакатонам) видел, что сильные люди склонны объединяться с сильными, слабые со слабыми, умные с умными, ну, в общем, Вы поняли… Примерно это и происходит в чатах: более менее сильные программисты тут же расхватываются, люди не обладающие какими-либо ценными для хакатона навыками, висят в чате подолгу и выбирают команду по принципу лишь бы кто-нибудь взял. На некоторых хакатонах практикуется случайное распределение по командам, причем организаторы утверждают, что рандомные команды показывают результат не хуже, чем уже сложившиеся. Но по моим наблюдениям, мотивированные люди, как правило, находят команду сами, если уж кого-то и приходится распределять, то, зачастую, многие из них и не приходят на хакатон.
Что касается состава команды, — это очень индивидуально и сильно зависит от задачи. Я мог бы сказать, что минимальный жизнеспособный состав команды — это дизайнер — фронтендер или фронтендер — бекендер. Но мне известны также случаи, когда побеждали команды, состоящие только из фронтедеров, которые приделывали простой бек на node.js, или делали мобильное приложение на React Native; или только из бекендеров, которые делали простую верстку. В общем, все очень индивидуально и зависит от задачи. Мой план по подбору команды на хакатон был следующим: я планировал собрать команду или присоединиться к команде типа фронтендер — бекендер — дизайнер (я сам фронт). И довольно быстро начал общаться в чате с бекендером на python и дизайнером, который принял приглашение к нам присоединится. Чуть позже к нам присоединилась девушка бизнес-аналитик, которая уже имела опыт победы на хакатоне, и это решило вопрос о её присоединении к нам. После короткого совещания мы решили назваться U4 (URBAN 4, урбанистическая четверка) по аналогии с фантастической четверкой. И даже поставили на аву нашего телеграм-канала соответствующую картинку.
4. Выбор задачи. Как я уже говорил, у Вас должно быть конкурентное преимущество, задача на хакатон выбирается исходя из этого. Исходя из этого, посмотрев список задач и оценив их сложность, мы остановились на двух задачах: каталог инновационных предприятий от ДПиИР и чат-бот от ЭФКО. Задачу от ДПИиР выбрал бекендер, задачу от ЭФКО выбрал я, т.к. имел опыт написания чат-ботов на node.js и DialogFlow. Задача ЭФКО также предполагала ML, я имею некоторый, не сильно большой, опыт в ML. И по условиям задачи мне показалось, что она, вряд ли, решается средствами ML. Это ощущение укрепилось, когда я сходил на митап Urban Tech Challenge, где организаторы показали мне датасет по ЭФКО, где было около 100 фотографий раскладок продуктов (сделанных с разных ракурсов) и около 20 классов ошибок раскладки. И, при этом, заказчики задачи хотели получить успешность классификации в 90%. В итоге, я подготовил презентацию решения без ML, бекендер подготовил презентацию по каталогу, и совместными усилиями, доработав презентации, мы отправили их на Urban Tech Challenge. Уже на этом этапе выявился уровень мотивации и вклада каждого участника. Наш дизайнер не принимал участия в обсуждениях, отвечал с запозданием и даже информацию о себе в презентации заполнил в самый последний момент, в общем появились сомнения.
В итоге, мы прошли по задаче от ДПиИР, и ничуть не расстроились, что не прошли по ЭФКО, поскольку задача показалась нам, мягко говоря, странной.
5. Подготовка к хакатону. Когда стало окончательно известно, что мы прошли на хакатон, начали готовить заготовку. И здесь я не призываю начать писать код за неделю до начала хакатона. Как минимум, у Вас должен быть готов boilerplate, с которым Вы можете сразу же приступить к работе, не занимаясь настройкой инструментов, и не натыкаясь на баги какой-то либы, которую Вы решили впервые попробовать на хакатоне. Мне известна история про ангулярщиков, которые пришли на хакатон и все 2 дня занимались настройкой сборки проекта, поэтому все должно быть подготовлено заранее. Мы предполагали распределить обязанности следующим образом: бекендер пишет краулеры, которые обшаривают интернет и кладут всю собранную информацию в БД, я же пишу API на node.js, который запрашивает эту БД и отдает данные на фронт. В связи с этим, я заранее сделал заготовку сервера на express.js, сделал заготовку фронтенда на react. Я не использую CRA, всегда настраиваю вебпак под себя и прекрасно знаю, какие это может таить в себе риски (помним историю про ангулярщиков). В этот момент я запросил заготовки интерфейса или хотя бы мокапы от нашего дизайнера, чтобы иметь представление о том, что я буду верстать. По идее, он тоже должен делать свои заготовки и согласовывать их с нами, но я так и не получил ответа. В итоге, я позаимствовал дизайн из одного своего старого проекта. И так стало получаться даже быстрее, поскольку все стили для этого проекта уже были написаны. Отсюда вывод: далеко не всегда в команде нужен дизайнер))). С этими наработками мы и пришли на хакатон.
6. Работа на хакатоне. Свою команду вживую я впервые увидел только на открытии хакатона в ЦДП. Мы познакомились, обсудили решение и этапы работы над задачей. И хотя после открытия мы должны были ехать на автобусах в Красный октябрь, поехали домой отсыпаться, договорившись придти на место к 9.00. Почему? Организаторы, видимо, хотели выжать максимум из участников, поэтому устроили именно такое расписание. Но, по моему опыту, можно нормально кодить, не спав одну ночь. А что касается второй, — я уже не уверен. Хакатон — это марафон, надо адекватно рассчитывать и планировать свои силы. Тем более, что у нас были заготовки.
Поэтому, отоспавшись, в 9.00 мы сидели на шестом этаже Dewocracy. Тут наш дизайнер неожиданно сообщил, что у него нет ноутбука, и что он поработает из дома, а общаться мы будем по телефону. Это стало последней каплей. И так мы из четверки превратились в тройку, хотя название команды не сменили. Опять же это не стало для нас сильным ударом, дизайн из старого проекта у меня уже был. В целом, сначала все шло достаточно гладко и по плану. Мы загрузили в базу данных (мы решили использовать neo4j) датасет инновационных компаний от организаторов. Я начал верстать, затем взялся за node.js, и тут пошли осечки. Я никогда ранее не работал с neo4j, и сначала я искал для этой БД рабочий драйвер, потом разбирался, как пишется запрос, а потом с удивлением обнаружил, что эта БД при запросе возвращает сущности в виде массива объектов нод и их ребер. Т.е. когда я запрашивал по ИНН организацию и все данные по ней, вместо одного объекта организации мне возвращался длинный массив объектов, содержащий данные по этой организации и отношений между ними. Я написал маппер, который проходил весь массив, и склеивал все объекты по организации в один объект. Но на бою при запросе к базе на 8 тысяч организаций он выполнялся крайне медленно около 20 — 30 секунд. Я задумался об оптимизации… И тут мы вовремя остановились и пересели на MongoDB, и это заняло у нас около 30 минут. В общей сложности на neo4j было потеряно около 5 часов.
Помните, никогда не берите на хакатон технологию, с которой Вы не знакомы, могут быть сюрпризы. Но, в целом, не считая этой неудачи, все шло по плану. И уже утром 9 декабря у нас было полностью рабочее приложение. Весь оставшийся день мы планировали накручивать на него дополнительные фичи. В дальнейшем, у меня все шло относительно гладко, а вот у бекендера был целый ворох проблем с баном его краулеров в поисковиках, в спаме агрегаторов юрлиц, который приходил в первых местах поисковой выдачи при запросе на каждую конкретную фирму. Но про это лучше расскажет он сам. Первая дополнительная фича, которую я прикрутил, — поиск по Ф.И.О. генерального директора ВКонтакте. Это заняло несколько часов.
Так, на странице фирмы в нашем приложении появилась ава ген.директора, ссылка на его страницу ВКонтакте и некоторые другие данные. Это была хорошая вишенка на торте, хотя возможно и не она обеспечила нам победу. Затем, я хотел накрутить какую-либо аналитику. Но после долгого перебора вариантов (возникало много нюансов с UI) остановился на самой простой агрегации организаций по коду экономической деятельности. Уже вечером, в последние часы, я верстал заготовку для отображения инновационных продуктов (в нашем приложении предполагается раздел Продукты и услуги), хотя бекенд под это был не готов. База при этом пухла как на дрожжах, краулеры продолжали работу, бекендер экспериментировал с NLP, чтобы отличать инновационные тексты от не инновационных))). Но уже подходило время сдачи итоговой презентации.
7. Презентация. По своему опыту могу сказать, что переключаться на подготовку презентации следует где-то за 3 — 4 часа до ее сдачи. Особенно, если в ней предполагается видео, его съемка и монтирование отнимает довольно много времени. У нас предполагалось видео. И у нас был специальный человек, который этим занимался, а также решал целый ряд других организационных вопросов. В связи с этим, мы до самого последнего момента не отвлекались от кодинга.
8. Питч. Мне не понравилось, что презентации и финал были вынесены в отдельный будний день (понедельник). Здесь, скорее всего, продолжилась политика организаторов по выжиманию из участников максимума. Я не планировал отпрашиваться с работы, хотел придти только на финал, хотя остальные члены моей команды взяли выходные. Однако эмоциональная погруженность в хакатон была уже настолько высока, что в 8 утра я написал в чат своей команды (рабочей, а не команды хакатона), что беру день за свой счет, и поехал в ЦДП на питчи. В нашей задаче оказалось очень много чистых дата сайентистов и это сильно сказалось на подходе к решению задачи. У многих был хороший DS, но ни у кого не было рабочего прототипа, многие не смогли обойти баны их кроулеров в поисковиках. Мы оказались единственной командой с рабочим прототипом. И мы знали, как решать поставленную задачу. В итоге, мы победили в треке, хотя нам очень повезло, что мы выбрали наименее конкурентную задачу. Глядя на питчи в других треках, мы осознавали, что у нас не было бы там никаких шансов. Также хочу сказать, что нам очень сильно повезло с жюри, они дотошно проверяли код. И, судя по отзывам, так происходило далеко не во всех треках.
9. Финал. После того, как нас несколько раз вызвали к жюри на code review, мы, подумав, что окончательно решили все вопросы, пошли пообедать в Бургер кинг. Там организаторы позвонили нам снова, пришлось спешно упаковывать заказы и возвращаться назад.
Организатор показал, в какую комнату надо пройти, и, зайдя туда, мы оказались на тренинге по ораторскому мастерству для победивших команд. Ребят, которые должны были выступать на сцене, хорошо зарядили, все выходили как заправские шоумены.
И должен признать, в финале, на фоне сильнейших команд из других треков, мы выглядели бледно, победа по номинации госзаказчика вполне заслуженно ушла команде из трека real estate tech. Думаю, что ключевыми факторами, внесшими свой вклад в нашу победу на треке, стали: наличие готовой заготовки, за счет которой и удалось быстро сделать прототип, наличие в прототипе «изюминок» (поиск ген.директоров в соцсетях) и навыки по NLP нашего бекендера, которые тоже сильно заинтересовали жюри.
И в заключение традиционные благодарности всем тем, кто за нас болел, жюри нашего трека, Евгению Евграфьеву (автору задачи, которую мы решали на хакатоне) и конечно же организаторам хакатона. Это был пожалуй самый крупный и крутой хакатон, из всех в которых я участвовал, остается только пожелать ребятам держать такую высокую марку и дальше!
Автор: PainKKKiller