Каждый Web App (веб-апп) — это маленькое и весёлое фронтенд-приключение.
Однажды в iFunny мы устроили «веб-апп марафон», развлекли миллионы пользователей и попутно заработали много денег. А теперь готовы рассказать, как же это всё было.
Для начала представлюсь. Меня зовут Антон, я тимлид фронтенд-команды FunCorp.
И в этой статье я поделюсь опытом разработки интерактивных веб-приложений на базе мобильного WebView.
WebAppView
WebView — это встроенный в мобильное приложение браузер.
А если есть браузер, значит, есть и обширные возможности HTML5, JS, CSS.
Это в теории. А как же на самом деле?
А на самом деле нас интересовали и другие вопросы:
- как хорошо примет новый формат аудитория iFunny?
- насколько проблемны в разработке такие приложения? Два года назад в компании отсутствовал опыт в этой части, и очень хотелось его наверстать;
- сэкономит ли данная технология время и деньги? Цикл разработки таких приложений короче, следовательно, такая возможность есть.
Web App #1: Hellowinner
В те времена команда состояла из двух человек и над всеми веб-аппами работал я один. С момента моего присоединения к команде прошло два месяца, поэтому с корабля я прямиком попал на «веб-апп бал».
Первое приложение было подготовлено к 31 октября — дню празднования Хеллоуина. С помощью мини-игры с двумя кнопками планировалось пощекотать нервы пользователям и вызвать вот такую реакцию:
Само же приложение выглядело вот так:
Пользователи с азартом ловили кнопку, приложение насмешливо приглашало делать это ещё быстрее. В момент Х на экране внезапно появлялась анимация с криками, звуками и вибрациями, что вызывало бурю эмоций. И не только у пользователей: при взгляде на этого зайца меня и сейчас слегка передергивает.
Технологический стек был простым:
- генератор статичных сайтов Harp;
- шаблонизатор Jade (ныне Pug);
- препроцессор LESS.
Генератор Harp предоставил полную инфраструктуру из коробки, так что я написал код, сгенерировал статичный сайт с CSS, HTML, JS, положил всё это дело на CDN, завернул в WebView и радовался. И было чему: первый опыт с веб-приложениями дал такой пик посещаемости, что позже каждый product-менеджер считал своим долгом придумать что-то интересное.
Web App #2: Putin vs Trump
Частично эта история упоминалась в статье про фейлы. Пришло время рассказать, как же всё было на самом деле.
В следующем веб-аппе было решено проводить опросы пользователей. Разумеется, в любимом формате — на скользкие и горячие темы. Первый опрос назывался President you want, и в нём нужно было выбрать Путина или Трампа.
В отличие от первого приложения, второе подразумевало наличие серверной части и работу с базой данных. На тот момент думалось, что это довольно просто и я, будучи фронтенд-разработчиком, справлюсь. Справился. С некоторыми оговорками.
В качестве базы данных я использовал MongoDB: API для мобильных клиентов iFunny крутился именно на данной системе, был готовый кластер, и выбор был очевиден. Express.js был выбран в качестве серверного фреймворка. Все тот же Jade (Pug) в качестве шаблонизатора, LESS в качестве препроцессора и сборка статики с помощью Gulp.
В первые часы после запуска нового приложения проголосовало свыше миллиона пользователей. И тут произошел курьёз: сумма процентов перевалила за 100%. Не 146% конечно, рядом.
Вместо того чтобы использовать стандартный инкремент из базы данных, я использовал банальное «текущее значение = текущее значение + 1». А про такое понятие, как конкурентность запросов, узнал вообще только в продакшене. Ну да, пустили слона в посудную лавку.
Получилось смешно, и пользователи восприняли это как хорошую шутку.
Я же исправлял ошибки глубокой ночью, дрожащими руками и с матами. Эти 10 тысяч запросов в секунду преподали хороший урок, и я пообещал себе больше так не делать.
Тот самый опрос, исправленный:
Web App #3: Booby Bird
После внушительных успехов предыдущих веб-аппов было решено запустить полноценную HTML5-игру. А так как в отделе по-прежнему работало 2 человека, разработка была поручена китайскому фрилансеру, которого нашли продакт-менеджеры.
Парень — молодец, постарался на славу:
- собрал игру в WYSIWYG-редакторе;
- написал серверную часть на PHP по мануалам со StackOverflow;
- скрепил эти части с помощью известного только ему одному клея;
- отдал результаты в виде обфусцированных файлов.
Мой оптимизм окончательно иссяк после того, как приложение наотрез отказалось запускаться на боевом домене. В итоге, я перенес код на уже проверенный Express.js и, насколько смог, внес заплатки в обфусцированный клиентский код. Игра ожила. Уже тогда было понятно, что конструкция хрупкая и держится на честном слове.
В конце игры был рейтинг лучших игроков и, разумеется, его сломали через 10 минут после релиза. Пользователи раскопали ссылку на сохранение результатов и массово принялись менять в ней значения. Я выпустил обновление, в котором персонализировал ссылку с помощью JWT-токена, и массовое окучивание топа закончилось.
Вот только я не мог защитить код, который целиком и полностью попадал к пользователю: обфускация разбиралась, а запросы по сети просматривались в соответствующих утилитах. Отдельные юзеры, которые умели пользоваться снифферами, снова разобрали ссылку с результатами и много разной ерунды туда послали. За что потом сами были отправлены в бан, благо идущий в комплекте JWT-токен оказался им не по силам.
Этот веб-апп всё же набрал приличное количество просмотров и, к нашему удивлению, имел очень длинный хвост повторных заходов.
Web App #4: Holiday Giveaway
На один из самых любимых американцами праздников — Рождество — была устроена лотерея, в которой разыгрывались приставки, подарочные карты, камеры, футболки и ряд других приятностей. Всего было проведено 4 розыгрыша, каждый в строго определённое время. После проведения очередного розыгрыша открывалась регистрация на следующий.
«Под капотом» были все те же Express.js, Jade (Pug), LESS. Ожидался большой пик посещаемости, и в качестве базы данных я использовал отдельный кластер MongoDB. И даже провел нагрузочное тестирование, чтобы вот в этот раз все точно получилось как надо. Ну, вы понимаете.
Веб-апп показал отличные результаты: около 3 миллионов участников уже в первом туре. Вот только вместе с успехом пришли и трудности.
Сначала проблема возникла в связке NGINX и PM2, который использовался для управления инстансами приложения. Мне искренне было страшно, я вообще не понимал, что делать: HTML5, CSS, JS, а тут какие-то таймвейты в сети, озадаченные DevOps-инженеры и молчаливый требовательный взгляд технического директора. Спустя некоторое время проблема была устранена, а до следующего розыгрыша призов был запас времени. Я наивно начал полагать, что теперь всё хорошо, отмучился.
И тут снова проблема: встроенный в серверную часть планировщик отказался делать второй розыгрыш. По какому-то наитию я решил проверить результаты работы скрипта и оказалось, что они отсутствовали. За окном была луна, локально дебажить проблему не получалось — всё работало, а время неумолимо шло против меня: приближалась публикация результатов второго розыгрыша. Спасло то, что я предусмотрительно оставил возможность ручного запуска. За минуту до публикации результатов розыгрыша я запустил скрипт, убедился, что он корректно отработал, и выдохнул.
Далее последовали бессонные ночные часы, в которых я держался как мог: смотрел фильмы, пробовал увлечься поиском ошибки, дремал в обнимку с будильником. В 3 часа ночи я запустил финальный розыгрыш, ещё раз всё перепроверил и уснул.
Такие жертвы были оправданы: спустя 24 часа у веб-аппа было более 12 миллионов просмотров, тысячи комментариев и большой шум по социальным сетям. Пользователи сильно взбудоражились: им определённо понравилось приложение. Да и мне понравилось, что скрывать.
Минусы и плюсы веб-аппов
Минусы:
- много слез было пролито с «Самсунгами», потому что WebView — это дефолтный браузер, а «Самсунги» очень любят все кастомизировать. И если десктопные браузеры, мобильные Chrome и Safari отображали веб-апп корректно, то у «Самсунгов» обязательно что-нибудь разносило. Эта марка очень популярна в США, приходилось чинить;
- после того как были устранены все проблемы отображения могло оказаться, что приложение некорректно работало в боевых условиях. И причина была банальной: если при сборке мобильного приложения забыли поставить пару галочек — и раз! — скролл в WebView уже не работал как надо. А это, скорее всего, новый релиз и минимум несколько дней отложенного запуска.
Плюсы:
- быстро. Среднее время разработки — две недели. Первая неделя — активная разработка, вторая — тесты, фиксы и доработка;
- дёшево. Экономия стоимости разработки огромная. Веб-апп может создать один фронтенд-разработчик для всех платформ. Дорогие мобильные девелоперы здесь не привлекаются. И даже если привлекаются, то редко и мало.
- круто. Формат действительно можно сделать интересным для пользователей. Судя по многим показателям (количеству комментариев, регистраций, времени сессий в играх), аудитории нравится такая интерактивность. Им нравится подмечать ошибки и смаковать их, нравится ломать и улетать в баны, нравится всё это дело обсуждать. А что может быть лучше подогретого и вовлечённого сообщества для UGC-продукта?
За период с сентября по декабрь было сделано 6 веб-аппов. И каждый из них дал хорошие результаты. «Веб-апп марафон» позволил ответить на все интересующие вопросы, в том числе на самый важный: да, это определённо стоящая тема, чтобы продолжать ей заниматься.
Сейчас разработка веб-аппов уже поставлена на поток: за прошедший 2017 их было 94, а по количеству сессий что-то около 101 миллиона. Кстати, большую часть можно посмотреть по ссылке.
Я же, в свою очередь, понял кое-что про работу в продуктовой компании.
Когда решался вопрос со сменой работы, я морально готовился к тому, что делать один продукт — это скучно, и мне скорее всего предстоит «пилить сайт» ближайшие 2 года. Когда же пришлось делать веб-аппы, обжигаться инкрементом, видеть больше 10К реквестов в секунду, руками ночью запускать скрипты — понял, как ошибался. Мне действительно приходилось «пилить продукт», правда, каждую неделю — новый. А это отличный фан и приличное развитие навыков.
К слову, те «ближайшие 2 года» мне всё-таки предстояло «пилить сайт», только в качестве новоиспеченного лида формировавшейся с нуля фронтенд-команды. Этот опыт повеселей веб-аппов будет. О нём расскажу в следующей статье.
Комментарии (13)
DimNS
08.02.2018 09:26«И причина была банальной: если при сборке мобильного приложения забыли поставить пару галочек»
Поделитесь пожалуйста этими галочками. Как раз намедни воевал с Самсунгами и тут раз и статья в тему.veretennikov Автор
08.02.2018 15:37У меня были две проблемы.
Во-первых, мобильный клиент работал с жестами. И как следствие, частично перехватывал управление. В итоге ребята из мобильной команды внедрили в клиент механизм, который для игр вообще отключал жесты. А для всего остального проверял эту необходимость по canScrollVertically.
Во-вторых, в самой верстке пришлось отказаться от overflow:hidden на корневых элементах. Это свойство препятствовало детектированию скролла в WebView.DimNS
08.02.2018 15:47Забавно, при этом весь код локально на десктопе всегда работал без запинки да? ))
veretennikov Автор
08.02.2018 16:22И на десктопе. И в мобильных браузерах на реальных устройствах. И в эмуляторах. Все самое интересное начиналось при открытии в WebView. Мы даже тестовые веб-аппы делали только для проверки возможностей в реальных мобильных клиентах.
DimNS
08.02.2018 16:40Сейчас для решения своих проблем копаюсь в интернете, и тут я вспомнил, а ведь есть такая штука как Crosswalk WebView Cordova Plugin (правда она для вас не подходит, а для меня в самый раз). Плагин тянет себе в apk свою версию хрома, увеличивая размер apk на 17 Мб, а размер установленного приложения на 50 Мб. Да крутой такой оверхед, но если задумываться о цене поиска и исправления всех будущих багов и глюков, то возможно можно и пожертвовать.
Хотя это такое себе решение, если все дружно так будут делать то общий оверхед зашкалит.
Возглас в пустоту: Ну почему тюнинговщики Андроида такие зас***цы и что-то там химичат со встроенным браузером (( Думаешь ну вот оно наступило счастье можно быстро и дешево делать приложения для мобильных устройств и тут такая подлянка.
alekciy
08.02.2018 10:2410к RPS? А какого рода запросы (статика? динамика)? Бэк — нода? Это пик запросов или среднее значение (медиана?)? Если это относительно постоянная нагрузка, то как долго держится и на каком железе?
veretennikov Автор
08.02.2018 16:2410К — это пиковое значение. Все запросы — динамические. Северная часть была написана на Node.js с использованием фреймворка Express.js. В качестве железа выступила пара инстансов Amazon EC2. Наибольшую нагрузку приложение получило сразу после публикации в основной ленте работ. Это вообще особенность всех наших веб-аппов — ощутимые нагрузки сразу же после публикации. И спокойная размеренная жизнь спустя пару часов.
cmohammedmedkeveo
08.02.2018 15:12А использовали cordova, ionic или что-то такое?
DimNS
08.02.2018 15:34Вот как раз с cordova сейчас воюю.
Приложение часть функционала подгружает с сервера (чтобы обновления выкладывать оперативно, без магазина, ничего незаконного всё честно).
Непонятные глюки были на самсунгах (Android 6), приложение подгружало первый скрипт с сервера но не выполняла его, хотя стояло событие на выполнение кода после полной загрузки скрипта. Порешал поставив таймаут в 2 секунды перед запуском кода загруженного скрипта, проблема исчезла.
Теперь вот сяоми (Android 6) тоже странности, в процессе работы меняется карточка питомца и подгружаются данные выбранного, дак вот данные успешно загружаются но на страницу применяются частично (часть данных остается от прошлого). Еще в процессе решения.
При этом весь код без проблем работает на десктопе в браузере Хром, вообще никаких глюков.
Вот теперь из статьи узнал что оказывается Самсунг какой-то свой браузер делают вместо встроенного.
P.S. В качестве фронта использую Framework7
DimNS
08.02.2018 15:50А чем вы тогда упаковывали приложения в WebView, своими силами через нативный код стандартными средствами разработки платформы Android, iOS?
veretennikov Автор
08.02.2018 16:16iFunny — нативный клиент. Поэтому все делалось стандартными средствами.
trigun117
Я думаю что если приложению не нужен офлайн режим, то это идеальное решение с точки зрения цена/качество.