Решил поделиться опытом разработки агрегатора цен на игры в Steam, который собирает информацию с почти трех десятков интернет-магазинов. Приложение полностью бесплатно. Не требует регистрации. И даже не содержит никакой рекламы. Пока только для Android, но версия для iOS на подходе.
Картошка — двигатель прогресса
В середине августа в ходе обычных трудовых будней я изучал различные сайты, собирающие информацию об актуальных скидках на ПК игры: IsThereAnyDeal, Hot Game, Gamefarm и другие. Заодно прошелся по ресурсам с бесплатными раздачами: Free Steam Keys, Free Game Keys, FreeSteam и прочим. Первая категория сайтов расстроила неудобством использования на мобильных (долгая подгрузка с 4G, плохая адаптивность, мелкие кнопки фильтров), вторая — неприятно удивила большим количеством навязчивой рекламы (надо же ребятам как-то зарабатывать).
Немногим позже, аккурат во время многочасового марафона по выкапыванию картошки на батиной даче (традиционная семейная забава), свое недовольство найденными ресурсами я сформулировал в логичный вопрос — почему у них нет мобильных приложений или хотя бы нормальной мобильной веб-версии? Ведь количество поисковых запросов с телефонов во многих регионах мира сравнялось или превысило запросы с десктопа еще в 2016 году. Ответа я не узнал, как и не нашел популярных приложений для сравнения цен на PC игры в App Store и Google Play. Почему? Если запрос рынка есть, а продукта нет, то может быть я ошибаюсь и необходимости в таком приложении нет? Или кто-то уже пытался запускать, не смог на этом заработать и закрыл проект?
Тут я повел себя как типичный мамкин стартапер и вместо полноценного исследования спроса ограничился общением с парой десятков приятелей-геймеров. Всем идея показалась интересной и они выявили желание воспользоваться подобным приложением. Столь нерепрезентативная выборка меня почему-то удовлетворила и в свободное от картошки и работы время я продолжил углубляться в тему.
Да так увлекся, что за пару недель раздумий набросал функциональный прототип приложения, продумал логику его работы и интерфейс. Не пропадать же добру?
Решено было довести дело до конца, т.е. разработать и выпустить приложение в релиз. Быстренько собрал команду из старых знакомых, написал ТЗ и с 1 сентября мы начали работу. Поставили для себя дедлайн — отправить первую стабильную версию на модерацию в Google Play 1 октября.
Спойлер: профакапили дедлайн ровно на 14 дней. Справедливости ради отмечу, что все члены команды заняты на постоянке, поэтому работа над приложение шла по вечерам и в выходные дни.
Технологический стек был выбран без изысков. Backend на Python, PHP, Django, Postgresql. Клиент пилился с помощью Flutter, дабы было проще зарелизить на обе платформы (возможно еще пожалеем об этом, время покажет). Прототипировали в Proto.io. Дизайнили в Figma. Ставили таски и вели документацию в Notion.
Тернистый путь к релизу
С первого же дня работы мы столкнулись с разными трудностями. Опишу некоторые из них.
Ни у кого из команды практически не было опыта работы над мобильными приложениями
Мы с товарищами делали онлайн-игры, аналитические системы, блог-платформы, рекламные сети, биржевых ботов и прочее. Но в мобильных приложениях мы понимали не больше, чем среднестатистический пользователь. И будем откровенны, это заметно невооруженным взглядом: косяки верстки, всевозможные костыли, не слишком удобные фильтры и сортировки, отсутствие модных эффектов и анимаций и т.д. Всему учимся на ходу, видим ошибки, переделываем что-то сразу, а что-то отправляем в бэклог на будущие релизы.
Нестабильность Steam API
Помимо мониторинга цен в сторонних магазинах мы дважды в сутки обходим весь каталог игр Steam, доступных для покупки в СНГ (таких около 40 800, включая DLC и прочее). Изначально задумывалось, что мета-данные игр (обложка, цена, разработчик, дата релиза, etc) будут подтягиваться запросом от клиента к серверам Steam. Но для нас стало неприятным сюрпризом, что такая большая корпорация как Valve не слишком заботится о стабильности — когда-то ответ от сервера Steam приходит за 0.2 секунды, когда-то за 10. И все это работает в один поток, за один запрос можно получить информацию только об одной игре. И это время нашему пользователю пришлось бы любоваться на ползунок загрузки.
Сэкономить на серверах нам не удалось, ок. Пришлось перенести всю логику приложения на backend. Зато, в теории, мы более стабильны и независимы. Все данные от Стима логируются на нашей стороне и даже в случае кратковременного падения серверов Valve мы будем работоспособны. Из дополнительных плюсов можно отметить гибкость в изменениях сортировок и фильтров, нам значительно реже необходимо обновлять клиентскую часть, чтобы улучшить качество core-функции приложения.
Ошибки в сторонних магазинах
Очевидно, что парсить только Steam и показывать его скидки — провальная затея. Таких приложений в мобильных сторах уже много и их ценность стремится к нулю. Зачем нужна прослойка, если официальное приложение Steam отсылает пуши по акциям на игры из вашего списка желаемого? Поэтому нашей основной фичей стал мониторинг магазинов, которые продают ключи с активацией в Steam, закупая их у издателей. Довольно быстро мы поняли, что человеческий фактор на стороне магазинов слишком высок. То и дело в нашей ленте скидок проскакивали дубли (когда контент-менеджер магазина случайно вбил одну игру два раза), некорректные названия игр и определение жанров.
Полной автоматизации добиться не удалось
Изначальный концепт был в том, что система функционирует абсолютно автономно. Наш сервер агрегирует данные со Steam и сторонних магазинов, а потом по API передает информацию в клиент. Мы хотели принципиально обойтись без ручных сортировок и даже внутренней админки, чтобы «машина» сама полностью управляла этим зоопарком из 40 800 тайтлов. Однако обрабатывать абсолютно все типы ошибок контентщиков магазинов оказалось слишком долго и сложно. Да и сам Steam опять подкинул проблем. По-умолчанию в нашем приложении стояла сортировка скидок, которую мы лаконично назвали «лучшие» — это лучшие предложения в соотношении абсолютной выгоды для покупателя.
Стало быстро понятно почему у всех существующих агрегаторов на первом экране отображаются не лучшие или новые скидки, а популярные тайтлы, которые курируются вручную. Уверен, что если бы пользователь при первом заходе увидел ситуацию как на скрине выше, то тут же бы удалил приложение и накатал гневный отзыв.
Помимо введения дефолтной ручной сортировки мы добавили в админке возможность скрывать игры — так проще всего чистить дубли и некорректные продукты. К тому же выяснилось, что некоторые инди-разработчики и издатели используют стратегию установки изначально завышенной цены, чтобы потом отдавать магазинам игры с дисконтом в 95%. В приложении это выглядело очень неуместно: открываешь вкладку скидок, а там 50 неизвестных сомнительных тайтлов подряд от одного издателя со скидкой 99%.
Магазины не торопятся делиться данными
И понять их можно. У всех крупных магазинов есть XML-фиды каталогов, которые в удобном формате передают информацию по играм. Это одно из требований к добавлению в Яндекс.Маркет. Но многие магазины не захотели делиться своими фидами с ноунейм ребятами, которые якобы создают какое-то там мобильное приложение. Вдруг мы вообще конкуренты, которые хотят попроще шпионить. Поэтому наш бот притворяется обычным юзером и раз в 30 минут проходит по всем страницам 27 (на момент написания статьи) магазинов, собирая с них данные по актуальным ценам.
У этого подхода есть очевидный минус — в случае значительного изменения структуры или верстки магазина наш бот спотыкается и разбивает нос в кровищу. Пока подобного не случалось, нам удалось пофиксить все известные проблемы, но вечно так продолжаться не может. Поэтому сейчас уже после выхода приложения в Google Play мы постараемся убедить магазины делиться с нами информацией в удобном формате.
Возможности приложения
Вкратце расскажу об основном функционале, который доступен в текущей версии.
Скидки
Сортировка скидок: хиты, лучшие (по соотношению профита), по размеру скидки в %, по размеру скидки в рублях.
Фильтры и поиск: по названию, по цене от и до, по % скидки от и до, по разработчикам, по издателям, по жанрам, по ОС.
Возможность добавить любую игру из списка в избранное одним тапом.
В карточке игры отображается обложка, основной жанр, дата выхода, разработчик, ОС и список всех магазинов, продающих эту игру с указанием актуальной цены и % скидки.
Раздачи
Здесь агрегируется информация по бесплатным раздачам игр и игровых сервисов. С указанием статуса (активная или закончилась), лаунчером (Steam, Uplay, EGS, etc), инструкцией по получению халявы и ссылкой на саму раздачу.
Избранное
Сюда заносятся все игры, которые вы лайкнули на других экранах. В будущем будет возможность настроить push-уведомления о новых скидках.
Монетизация
На данный момент ее просто нет. Приложение полностью бесплатно и не содержит никакой рекламы.
С момента непосредственного начала работы над приложением и до отправки стабильного билда в Google Play прошло ровно 45 дней. За это время мной было потрачено ровно 106 000 рублей — это оплата работы ребят, аренда сервера и доступ к сервису прототипирования.
В будущем для вывода проекта на самоокупаемость я хотел бы добавить партнерские ссылки от магазинов. Если вы вдруг из приложения перейдете на сайт интернет-магазина и совершите там покупку, то я буду получать 2-5% от стоимости. Не волнуйтесь, с вас никаких комиссий не будет, магазины платят её из собственной маржи. Но тут я абсолютно без иллюзий, прекрасно понимаю, что многие магазины ПК игр слишком неудобны в использовании с мобильных телефонов и большинство будет использовать наше приложение исключительно как источник информации, а покупать с компьютера. Вероятно, доход с партнерских ссылок не будет покрывать даже расходы на сервера и поддержку проекта. Однако это не страшно, планов по бездумной баннерной монетизации у меня нет, зато есть возможность и желание поддерживать и развивать проект за счет личных средств.
Планы на следующие апдейты
Та версия, что сейчас доступна в Google Play — первая стабильная итерация. Roadmap по дальнейшим улучшениям расписан на несколько месяцев вперед.
Вот лишь несколько пунктов из него:
- Релиз в App Store.
- Возможность необязательной авторизации через Steam — позволит реализовать фильтр по wishlisted и скрывать игры, которые у вас уже куплены.
- Возможность самостоятельно добавлять игры в игнор. Сейчас частенько одни и те же игры красуются на первых позициях ленты скидок, если они вам надоели, то можно будет их скрыть.
- Новые фильтры: по типам продуктов (игра, DLC, etc), по конкретным магазинам, по дате выхода игры.
- Новые сортировки: по оценкам Metacritic и пользователей Steam, по популярности внутри нашего приложения (количество добавлений в избранное) и по персональным рекомендациям (приложение будет смотреть чем вы интересуетесь и сможет рекомендовать лучшие скидки исходя из этого).
- Мониторинг не только Steam, но и других лаунчеров — сейчас иногда такие игры тоже выдаются, когда одна игра есть в нескольких лаунчерах, но это скорее можно считать ошибкой.
- Выбор языка и валюты — хотим быть полезны не только геймерам из СНГ, но и всем в мире. Для этого будем парсить все самые крупные магазины из других стран и персонализировать выдачу исходя из языка и валюты пользователя.
- Персонализированные уведомления о скидках — хотели делать на старте, но быстро поняли, что в первом приближении приложение заваливает пушами как из автомата. Нужно детальней продумать логику их отправки и дать юзерам возможность гибкой настройки.
Если любопытно, вот здесь я создал открытую доску в Trello, на которой мы отражаем текущий статус разработки и список известных нам багов.
Титры и благодарности
Хочу выразить благодарность отцу и его бескрайнему картофельному полю, которое дало мне множество часов на раздумья. Проводить время с семьей — бесценно!
Огромное спасибо команде проекта — Саше (backend), Егору (клиент), Паше (система управления контентом) и Валере (дизайн) — ребята, вы большие молодцы! И да, я прекрасно понимаю, что некоторые из вас взяли бы за подобную работу в 2-3 раз больше денег, если бы это был сторонний заказчик.
В конце материала еще раз напомню ссылку на приложение Game Hunters в Google Play.
И еще, у нас в команде не было тестера, поэтому отловить все возможные ошибки не представлялось возможным. Как не удалось и провести полноценное нагрузочное тестирование. О части косяков мы уже знаем и работаем над их устранением, но пинок никогда не будет лишним. Ну и напомню, что список на исправление лежит в Trello.
Отдельно лишь отмечу «баг», который проявляется в том, что цена в нашем приложении и на странице товара в магазине иногда может отличаться. Это не ошибка, а следствие того, что мы парсим игры раз 30 минут, а не в реальном времени. Пожалейте наш сервер. Порой случается, что магазин уже обновил цену, а следующего обхода бота еще не произошло.
Предлагать идеи по улучшению, ругаться на баги и ожидать релиза на iOS (̶с̶ч̶а̶с̶т̶ь̶е̶ ̶н̶е̶ ̶з̶а̶ ̶г̶о̶р̶а̶м̶и̶) можно в нашем паблике ВКонтакте.