- PVSM.RU - https://www.pvsm.ru -

DIY: Как мы делали «живое» расписание для Codefest X

В конце марта в Новосибирске отгремел юбилейный 10-ый CodeFest [1]. Как и, наверное, любая конференция, CodeFestX оставил участникам кучу разных впечатлений от «ноги моей тут больше не будет» до «как купить пожизненную подписку?». То, как это было я описывать не буду, отзывы уже есть [2] и, думаю, еще появятся. Хочу поделиться историей того, как мы запустили альтернативную версию для расписания Codefest [3] (смотреть лучше с мобилки): от идеи до получившегося результата.

DIY: Как мы делали «живое» расписание для Codefest X - 1

Идея

Я посещаю Codefest начиная с 2010 года, и в этом году была моя 9-ая конференция. Для меня Codefest — это традиция, и в этот раз захотелось сделать что-нибудь полезное. До начала мероприятия, читая чат конференции, я понял, что расписание — это то, что точно можно улучшить. Codefest — насыщенное мероприятие, из которого всем хотелось бы выжать максимум, поэтому я решил помочь с построением альтернативного настраиваемого расписания.

Цели были намечены следующие:

  • Для посетителей — дать возможность получить больше актуальной информации о происходящих событиях и сформировать свою ленту интересов. Плюс у всех посетителей конференции была возможность прийти на наш стенд и запилить любую недостающую фичу или пофиксить баг;
  • Для Codefest — это дополнительный канал распространения «народной» программы;
  • Для нас как компании — это, конечно же, дополнительный плюсик в Employer-бренд.

DIY: Как мы делали «живое» расписание для Codefest X - 2

Концепция «прокаченного» расписания зашла организаторам Codefest. Я поделился идеей в Wrike и быстро нашел единомышленников, готовых подключиться. Начали с исследования, посмотрели на сайты конференций и мобильные приложения. В общем, запустили обычный продуктовый процесс [4] в Wrike.

В результате проработки бэклога определились, что необходимый функционал нужен такой:

  • Основное расписание конференции с возможностью фильтрации докладов и поиска;
  • Избранное и нотификации о приближении избранных событий;
  • Народная программа, с тем же функционалом, что и основная, а также возможность для партнеров и активистов добавлять события в эту программу.

Были задачи с приоритетом пониже:

  • Обсуждения по докладу, чтобы авторизованные пользователи могли обмениваться мнениями и дискутировать;
  • Лайки и народный рейтинг докладов;
  • Карта, т.к. CodeFest большой, и навигация очень важна.

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

Реализация

В качестве стека для проекта решили взять то, что используем в разработке нашего продукта, чтобы дать возможность посмотреть, как строится frontend в Wrike. Мы пишем на Dart [5] (и уже рассказывали почему: здесь [6] и здесь [7]) и ПОКА [8] для больших web-проектов, вроде нашего, есть только Angular (вот 5 минут вдохновения [9] от bunopus [10]). Репозиторий нашего проекта можно найти тут github.com/wrike/codefestx [11].

В нашем приложении к Angular мы добавили Redux [12]. Для Dart есть несколько имплементаций: мы взяли Redux.dart [13] и Redux Epics [14] для эффектов. У нас в проекте относящийся к Redux код находится тут github.com/wrike/codefestx/tree/master/lib/src/redux [15].

Для работы с неизменяемыми состояниями (immutable state) мы взяли пакеты built_value [16] и built_collection [17], которые хорошо упрощают работу. Например, мы создаем класс для state нашего приложения — CodefestState [18], а пакеты генерируют билдер [19].
Для связи Angular и Redux используется нехитрый прием (в основном компоненте — github.com/wrike/codefestx/blob/master/lib/app_component.dart [20]):

И их мы связываем вместе через стандартный дартовый Stream [24]:

_dispatcher.onAction.listen((action) => _store.dispatch(action)),
_store.onChange.listen((_) => _zone.run(_cdr.markForCheck)),

То есть, при создании в диспетчере действия (все они находятся тут [25]), оно попадает в хранилище Redux. Идет его обработка и меняется состояние, что вызывает цикл ангуляровского Change Detection.
Для отправки уведомлений сделали 2 механизма: для уведомлений о наступлении событий, т.к. это важно, интегрировались с PushWoosh [26] и получили системный push (к сожалению без поддержки браузеров на iOS). Для менее критичных событий, например, выхода новой версии, подняли сокет, а на клиенте использовали socket_io_client [27].

DIY: Как мы делали «живое» расписание для Codefest X - 3

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

Инфраструктура

В современном мире, чтобы выложить JS файлик для всеобщего пользования, без k8s [28] не обойтись. А если серьезно, то одна из возможностей нашего сервиса — это его доработка прямо на самой конференции (чем воспользовалось несколько Dartизан среди посетителей и нет, они не из Wrike :)).

DIY: Как мы делали «живое» расписание для Codefest X - 4

Поэтому решили сделать честный CI. Поглядели на те возможности интеграции, которые есть у GitHub [29], и нашли там Google Cloud Build [30]: раз уж используем продукты Google, то не сходить же с этой дорожки. Интеграция работает так: любой коммит в репозиторий вызывает сборку cloudbuild.yaml [31]. Мы пошли по пути, что собираем Docker контейнер с готовым приложением (благо шаблон для дарта есть — hub.docker.com/r/google/dart [32]), а затем запускаем его в k8s, чтобы была возможность откатывать релизы, масштабироваться и предусматривать прочие гипотетические ситуации. Из того, чего не хватило из коробки — это возможности делать разное поведение в зависимости от ветки, куда делаем коммит, то есть, чтобы для master сборка проходила и развертывалась в бой, а для остальных веток, выполнялись минимальные шаги, без участия k8s. Есть активное обсуждение этой темы тут [33], и мы воспользовались решением из этой дискуссии. CI отработал на отлично и ни разу не подвел.

Ложка дёгтя

Помимо наших успехов, конечно же, есть и то, что можно было сделать по-другому. Например, не заставлять людей авторизовываться при голосовании за доклады — некоторые это не любят (тем более в краткосрочных сервисах). В итоге, мы получили не очень много «лайков» за доклады, но, тем не менее, поздравили спикеров-чемпионов.

DIY: Как мы делали «живое» расписание для Codefest X - 5

Еще мы в кураже web-разработки забыли о жестких ограничениях iOS, и что там нет возможности делать push для web [34]. Оказалось, что почти половина пользователей нашего сервиса были с iPhone. Им мы, к сожалению, не смогли послать уведомление.
И что еще расстроило команду, как я уже упоминал, — не всё задуманное успели сделать. Часть функционала выкатывали прямо на конференции, а часть еще живет в backlog.

Результаты

Спасибо организаторам, что ссылка на расписание была добавлена в памятку участника конференции. Во время конференции сервисом воспользовалось более 1100 пользователей. К основной программе из ~120 событий, мы добавили еще ~50 «народных». Примерно 75% сессий пришлось на мобильные девайсы, мы отправили более 500 push-уведомлений, выпустили 3 релиза за время самой конференции, получили кучу удовольствия от процесса и результата.

DIY: Как мы делали «живое» расписание для Codefest X - 6

Это был классный опыт, а мы продолжим развивать проект, как минимум для внутренних событий и конференций Wrike. Если вы были на Codefest и пользовались нашим расписанием, будем рады вашим отзывам в комментариях.

Автор: Demetrikl

Источник [35]


Сайт-источник PVSM.RU: https://www.pvsm.ru

Путь до страницы источника: https://www.pvsm.ru/razrabotka/315055

Ссылки в тексте:

[1] CodeFest: https://2019.codefest.ru/

[2] уже есть: https://youtu.be/N1oy7dGuSEI

[3] альтернативную версию для расписания Codefest: https://codefest.wrike.tech/welcome

[4] продуктовый процесс: https://youtu.be/aMLS3sr0diE

[5] Dart: https://www.dartlang.org/

[6] здесь: https://habr.com/ru/company/wrike/blog/330832/

[7] здесь: https://habr.com/ru/company/wrike/blog/330900/

[8] ПОКА: https://medium.com/flutter-io/hummingbird-building-flutter-for-the-web-e687c2a023a8

[9] 5 минут вдохновения: https://youtu.be/0mHspoS5Zf8

[10] bunopus: https://habr.com/ru/users/bunopus/

[11] github.com/wrike/codefestx: https://github.com/wrike/codefestx

[12] Redux: https://hackernoon.com/redux-step-by-step-a-simple-and-robust-workflow-for-real-life-apps-1fdf7df46092

[13] Redux.dart: https://pub.dartlang.org/packages/redux

[14] Redux Epics: https://pub.dartlang.org/packages/redux_epics

[15] github.com/wrike/codefestx/tree/master/lib/src/redux: https://github.com/wrike/codefestx/tree/master/lib/src/redux

[16] built_value: https://pub.dartlang.org/packages/built_value

[17] built_collection: https://pub.dartlang.org/packages/built_collection

[18] CodefestState: https://github.com/wrike/codefestx/blob/master/lib/src/redux/state/codefest_state.dart

[19] билдер: https://github.com/wrike/codefestx/blob/master/lib/src/redux/state/codefest_state.g.dart

[20] github.com/wrike/codefestx/blob/master/lib/app_component.dart: https://github.com/wrike/codefestx/blob/master/lib/app_component.dart

[21] здесь: https://webdev.dartlang.org/angular/note/effective/change-detection

[22] здесь: https://github.com/johnpryan/redux.dart/blob/master/doc/why.md

[23] github.com/wrike/codefestx/blob/master/lib/src/redux/services/dispatcher.dart: https://github.com/wrike/codefestx/blob/master/lib/src/redux/services/dispatcher.dart

[24] Stream: https://www.dartlang.org/tutorials/language/streams

[25] тут: https://github.com/wrike/codefestx/tree/master/lib/src/redux/actions

[26] PushWoosh: https://www.pushwoosh.com/

[27] socket_io_client: https://pub.dartlang.org/packages/socket_io_client

[28] k8s: https://kubernetes.io/

[29] GitHub: https://github.com/marketplace/category/continuous-integration

[30] Google Cloud Build: https://cloud.google.com/cloud-build/

[31] cloudbuild.yaml: https://github.com/wrike/codefestx/blob/master/cloudbuild.yaml

[32] hub.docker.com/r/google/dart: https://hub.docker.com/r/google/dart/

[33] тут: https://github.com/GoogleCloudPlatform/cloud-builders/issues/138

[34] нет возможности делать push для web: https://help.pushwoosh.com/hc/en-us/community/posts/360000826663-Mobil-Safari

[35] Источник: https://habr.com/ru/post/448610/?utm_campaign=448610