Вроде бы о тестировании мобильных приложений есть уже тысячи материалов, так что удивить тут сложно. Но пока аспекты вроде UI уже затёрты до дыр, про тестирование геолокации рассказывают гораздо реже. И когда на нашей конференции Heisenbug Николай lamamer Козлов и Александр z3us Хозя (Badoo) поделились своим опытом, зрителей конференции доклад очень заинтересовал. Как и геолокацию получить, и телефон пользователю не разрядить? Зачем в этом тестировании селфи-палка? Насколько близко расположены лондонские пабы и что из этого следует?
Мы решили, что аудитории Хабра он тоже может быть интересен, и выкладываем его сразу в двух версиях: для любителей посмотреть видеозапись, а для любителей читать под катом текстовая версия.
Александр Хозя:
Давайте сначала познакомимся. Меня зовут Александр Хозя, в компании все называют по фамилии «Хозя», я к этому привык, можете тоже ко мне так обращаться. Я заведую всем ручным мобильным тестированием в компании Badoo, не люблю все мобильные операционные системы примерно одинаково, и сегодня буду говорить про iOS.
Николай Козлов:
Меня в компании по фамилии зовут «Козя», я тоже к этому привык. Обожаю гаджеты, особенно на операционной системе Android и вообще Unix-подобные. Не люблю iOS: имею Apple Watch и iPhone только чтобы понимать, насколько ненавижу их хороший сервис и качество обслуживания.
Немного о нас. Наверное, вы уже знаете, что Badoo — это сервис для поиска новых знакомств. У нас более 360 миллионов пользователей (из них 60 миллионов активных в месяц), и порядка 300 000 регистраций в день. Они генерируют 350 миллионов сообщений в день.
Что касается непосредственно нашего доклада. Чтобы вы понимали объем данных, который приходится обрабатывать нашим бедным серверам: наши пользователи в день генерируют порядка двух миллиардов координат. Эти два миллиарда генерируют около 10 миллионов «пересечений» — о том, что такое пересечения, расскажем чуть-чуть позже.
При этом все, что мы описываем далее, возможно только с тестовыми пользователями. Доступа к данным реального пользователя у нас нет, за исключением случая проверки какой-то аномалии или бага, и даже в этом случае нужно разрешение самого пользователя на данное действие.
Так вот, о чем сегодня мы поговорим:
Давайте для начала вспомним, что вообще такое геолокация, с чем ее едят, и как она работает в современных девайсах.
Исторически она появилась в iOS с релизом версии 2.0 в 2008-м, и тогда ваш телефон научился «вычислять по IP». Проблема была в то, что Geo IP дает низкую точность: в лучшем случае это будет улица, а в случае с мобильным девайсом обычно страна, потому что IP-адреса в большинстве случаев плавающие (у оператора в каждом регионе свой диапазон адресов, который зачастую никак не привязан географически).
В дальнейшем инженеры решили воспользоваться так называемым Cell ID. Принцип работы достаточно прост: мы знаем местоположение базовых точек в пространстве, и зная уровень сигнала от этих точек, можем примерно определить расстояние до них. Дальше рисуем большое количество кругляшков, и где-то в области наложения всех окружностей оказывается пользователь. Точность уже возросла: в небольших городах это 1000 метров, а в городах вроде Москвы, где базовых станций намного больше — это 60 метров. А при использовании Wi-Fi, Bluetooth и других beacon можно повысить точность до 10 метров, что очень удобно: не надо использовать следующую систему, которая называется GNSS, или глобальная навигационная спутниковая система.
Почему я говорю не «GPS»? Потому что на рынке навигационных систем существует несколько игроков. Основные — это GPS, GLONASS, китайская BeiDou и европейская Galileo. Кроме того, существуют две региональные навигационные системы — индийская IRNSS и японская QZSS («Квази-зенитная навигационная система»). Почему систем так много? Все системы двойного назначения, при необходимости в определенных случаях можно их отключить. Также некоторые системы нужны, чтобы уточнять местоположение, потому что в Индии и Японии есть известное смещение спутников GPS, которое нужно все время высчитывать, это лишняя головная боль. Японцы любят точность, и после введения QZSS достаточно всего лишь двух спутников, чтобы точность составила в худшем случае 10 сантиметров, а в лучшем случае один сантиметр.
При этом главная проблема всех навигационных систем — это холодный старт. У девайса, который только что был выпущен с завода и еще ни разу не получал геолокацию, при самом первом запуске холодный старт без A-GPS составит 15 минут: 12 с половиной минут он будет качать атлас звездного неба, и еще две с половиной минуты уйдут, чтобы получить сигналы со спутников. Это большая проблема, и поэтому придумали систему A-GPS: используя Geo IP и Cell ID, телефон быстренько определяет примерное местоположение и посылает это на специальный сервер, который отдает атлас. А через 2-3 минуты (в большинстве случаев даже меньше) телефон быстро находит спутники, и показывает вам, где вы находитесь, очень удобно.
Теперь давайте поговорим, для чего вообще нужна геолокация. Прежде всего — для персонализации контента.
Если ваш продукт — система навигации, и вы не используете геолокацию, скорее всего, пользователи его использовать не будут. Если вы делаете какое-то рекламное приложение, тоже возможна персонализация: вы проходите мимо какого-то магазина, телефон это понял, и срабатывает push-уведомление, что именно сейчас в этом магазине для вас скидка 50%. В дейтинге геолокация тоже очень важна. Наши пользователи хотят видеть тех, кто находится в их городе, а желательно вообще как можно ближе. И не хотят видеть пользователей из других стран. При помощи геолокации мы решаем эту и много других задач.
Все улучшения, связанные с геолокацией, мы разрабатывали для сервиса «Пересечения», о котором Саша расскажет чуть позже. Я скажу лишь, чтобы было понятно, как это должно работать с точки зрения пользователей, логики. Но было совершенно непонятно, как получать как можно большее количество координат и геоданных при как можно меньшем энергопотреблении. Это был 2014 год, было много информации о том, как это все реализовывать на стороне клиента, но абсолютно не было информации о том, как это нужно тестировать. К сожалению, все приходилось находить самому, и самому создавать документацию с нуля. А теперь давайте поговорим, где и как мы пользуемся геолокацией.
Хозя:
Самый первый наш главный экран — это знакомства, где пользователя голосуют друг за друга. Как Коля уже говорил ранее, значительно интересней находить людей и общаться, когда они находятся рядом с вами, поэтому геолокация — это один из самых главных весов, по которому наш сервер выдает пользователей друг другу.
У нашего следующего экрана говорящее название «Люди рядом», где в самой первой секции вы видите людей, которые находятся максимально близко к вам. Если, конечно, вы дали нам доступ к нашим сервисам геолокации. Если не дали, то мы вас попросим ввести хотя бы город. Открываете профили пользователей и видите, что они находятся рядом с вами: допустим, Алена была на расстоянии 300 метров от нас.
На этом же экране мы как раз показываем пересечения, и настало время рассказать, как же это все работает. В теории не очень сложно: вы двигались и в определенный момент траектории движения вас и других пользователей либо пересеклись в конкретной точке, либо вы были максимально близко друг от друга (например в 20 метрах). Если вы пересеклись с одним пользователем, то мы генерируем персонализированный push. Проверяем, общались ли вы с этим пользователем, допустим, вы его лайкнули или переписывались, он вас добавил в избранное, и т.д. Отправляем персонализированный push, можно открыть его профиль, увидеть, что пересеклись примерно в таком-то местоположении (примерно для того, чтобы избавиться от всяких злобных редисок, которые захотят вас встретить в подворотне). Если вы пересеклись сразу с 3-4 людьми, мы вас приземляем на экран «люди рядом», и пользователи, с которыми вы пересеклись, помечены там специальной галочкой.
Также геолокацией можно поделиться в чате либо запросить ее, допустим, чтобы пользователь подошел к вам: вы находитесь в какой-то кафешке, отправили геолокацию, очень удобно.
А также в одном из наших побочных продуктов геолокация используется для чекинов. В принципе, плюс-минус Swarm, но про дейтинг. Допустим, вы ходите в один и тот же стейк-хаус, и вам интересно, кто еще туда ходит, чтобы пообщаться о стейках. Либо вы пришли в клуб, запустили приложение и видите, что в данный момент в клубе 24 человека. Как показывают наши данные, нахождение общего места повышает шанс получения сообщения примерно на 40%, это очень много. Также мы используем геолокацию в антиспаме.
Козя:
В первую очередь, мы затрудняем триангуляцию нашими пользователями других пользователей. Дальше мы, используя геолокацию, можем определить, что пользователей резко сменил свое местоположение, и тут может быть два случая. Либо сработал антиспам, пользователь решил переместиться в другую страну, и докучать других пользователей, либо у пользователя угнали аккаунт в хакеры из другой страны. Мы в таких случаях принимаем меры.
Помимо этого, для сервиса пересечений мы разработали так называемый «Режим таксиста». Люди, которые постоянно двигаются по городу с включенным навигатором, генерируют очень много точных геоданных. Понятное дело, что у них будет много пересечений. Чтобы эти пользователи не примелькались и не докучали другим пользователям, у них пересечения генерируются по специальному алгоритмам с более жестокой фильтрацией.
Мы поговорили, чем хороша геолокация, где мы ее используем, давайте поговорим о другой проблеме, а именно проблеме сбора геоданных.
Это временной график, и от момента старта вашего приложения до момента получения геолокации с заданной точностью может пройти время. Чтобы получать геолокацию быстрее, придется дополнительно использовать неэкономичные с точки зрения аккумулятора датчики — барометр, гироскоп и т.д. Но даже при использовании всех возможных датчиков, которые есть на девайсе, нет гарантии получения точности заданных координат.
Давайте почитаем определение точности непосредственно в документации Google: «Точность — это радиус вокруг точки, внутри которого с вероятностью 68% находится пользователь».
Или, проще говоря, с вероятностью 68% мы находимся прямо сейчас где-то здесь.
А можем и не находиться. Как вы видите, пришло две точки, и расстояние между ними намного меньше, чем точность, которую они выдают. С такими геоданными тоже необходимо уметь работать.
Получение точных геоданных зависит от времени, они могут не прийти вообще, это нужно уметь обрабатывать. Давайте поговорим, как протестировать сборку и отсылку локаций, не выходя из офиса, на самых ранних этапах: когда нужно проверить, что ваша система вообще умеет хотя бы как-то принимать геолокацию.
Для этого разумно использовать простейшие доступные средства, например, эмулятор Android. В режиме эмуляции локации содержит простейшие вещи, такие как эмуляции самой локации, и загрузка GPX-маршрута, о которой Саша попозже расскажет.
Любопытно, что дефолтная локация Android-эмулятора — деревня Далвик в Исландии. Dalvik — это виртуальная машина в Android до версии 5.0.
С другой стороны, на iOS почему-то, я сам не понимаю почему, симулятор намного богаче.
Хозя:
Да, действительно так. Обычно Apple очень дружественен к пользователям, но у инженеров вызывает огромную попаболь. Однако в этом случае в Apple подумали о нас, и нам доступны целых 3 варианта движения: пробежка, поездка на велосипеде и езда по трассе.
Удобно это тем, что система возвращает нам все необходимые данные о самой координате, скорость, вектор движения, горизонтальную и вертикальную скорость, а в некоторых случаях даже этаж. Очень удобно для тестирования геолокации, не выходя из офиса.
Но иногда, если вы свернете приложение в бэкграунд, система не будет присылать вам координат вообще. Это баг либо Xcode, либо симулятора, либо самой macOS. Чтобы это победить, нужно будет либо убить Xcode, либо симулятор, а если ничего из этого не помогло, то перезагрузиться. Но если вы запустили симулятор и у вас все работало, а потом после каких-то манипуляций перестало, скорее всего, это все-таки баг в вашем приложении.
Следующее, что мы используем — наша любимая среда разработки Xcode. Подключаемся дебаггером либо к симулятору, либо к реальному девайсу (это важно, немногие знают, что на реальном iOS-девайсе можно симулировать геолокацию), нажимаем на синюю стрелку, либо в меню выбираем Debug > Simulate locations, и видим выпадающий список с точками, которая Apple добавила — Москва, Лондон и т.д. Но нас интересует кнопка «Add GPX File to Workplace» в самом низу, которая позволяет добавить GPX маршрут.
Чтобы его сгенерировать, я рекомендую пользоваться Maps to GPX converter. На вход он принимает трассу из Google Maps — как полную URL, так и сокращенную. На выходе генерирует вам GPX-файл: на самом деле, это просто подмножество XML со временем и точкой в пространстве, дальше система сама интерполирует все это дело. Этот GPX-файл совместим с Android, iOS и Windows Phone, GPS-трекерами и т.д.
На самом деле этот инструмент был создан во времена бума Pokemon Go, спасибо им за это, очень сильно облегчило нам тестирование. Единственное, что если мы сгенерируем этим инструментом GPX-файл, система не будет определять скорость движения на iOS, поэтому, если вам нужно знать именно скорость, лучше использовать симулятор.
Давайте теперь поговорим про зеленое ведерко.
Козя:
Так как мы заметили, что эмулятор не такой богатый, как симулятор iOS, мы воспользовались тем, что мы можем поставить любое приложение без ограничений.
Первое приложение, которым я рекомендую воспользоваться — это Lockito, очень удобное, фактически заменяет вам симуляцию тех трасс, которые есть у Apple. Смысл в чем: вы запускаете приложение, указываете точки в пространстве, тип перемещения между этими точками (будь то по прямой или каким-то видом транспорта) и параметры выдачи координат, скорости и т.д. Запускаете симуляцию, после чего просто смотрите в вашем приложении, как вы вроде бы двигаетесь в пространстве.
Второе приложение — GPS Status & Toolbox. Чем удобен: его можно запустить в многооконном режиме, и посмотреть, как ваше приложение выглядит на маленьких девайсах, непосредственно на вашем большом девайсе. Ну и показать, что выдает система геоданных вашего девайса, что получает ваше приложение, и сравнить это. Если вы попали в какую-то аномальную зону, когда ваше местоположение не соответствует реальному местоположению (например, вас вдруг перебросило во Внуково), можете использовать GPS Test, чтобы понять, почему так произошло.
Учтите, что при использовании Lockito надо уметь пользоваться Location Mock, если ваше приложение пользуется библиотеками, которые решают за вас задачу использования каких-либо источников геоданных, о которых я говорил дальше. И если у вас в Android по умолчанию включены все источники геоданных, то вас будет часто перебрасывать при симуляции обратно в точку, где вы находитесь на данный момент. С чем это связано: любое приложение, которое эмулирует локацию, эмулирует только подсистему GPS, поэтому в настройках надо переключить такие источники данных, как GPS-данные, и все будет хорошо.
Давайте немножко резюмируем: мы поняли, что Maps to GPX Converter — это очень хорошо, можно загрузить одновременно GPX-файл на разные девайсы, и посмотреть, как различные операционные системы будут обрабатывать одинаковые маршруты. Ну и из коробки iOS, к сожалению, побогаче Android, зато Android зеленый, красивый и вообще лучше!
Теперь мы поняли, что наша система принимает данные. Теперь надо понять, что что-то хоть как-то работает, то есть начинать тестировать бизнес-логику.
Для начала мы столкнулись с тем, что наша бизнес-логика была слишком большая, и мы не могли удержать все в голове. В чем была проблема: у нас было большое количество файлов, фич и классов, отвечающих за ту или иную систему обработки локаций. Чтобы снизить интервалы обработки геоданных или расстояние между получением координат, нужно было это все искать, менять, собирать приложение, и мы могли что-то пропустить, потому что в голове все не удержишь.
Для этого мы создали удобный файл конфигурации. Вот пример файла конфигурации на iOS, где вы просто можете поменять все необходимые данные, с вашим любимым Xcode собрать приложение и начать им пользоваться.
Хозя:
Следующая проблема, с которой мы столкнулись — это информационный шум, потому что без доказательств существования багов (допустим, скриншотов и подробных логов), разработчик зачастую может даже не понять, в какую сторону начинать копать. При тестировании геолокации это усугубляется тем, что в уравнении очень много переменных. Там не то что баг сложно воспроизвести, там иногда получить дважды подряд тот же самый набор координат с заданной точностью не представляется возможным. Поэтому без логов тестирование может создать больше информационного шума, чем реальной пользы, вы будете просто отвлекать ваших девелоперов.
Также, будем реалистами, зачастую разработчики добавляют логи для себя. Но даже если они добавляют логи для тестирования, зачастую они не до конца понимают, что нам нужно. Поэтому в нашем случае мы видели только координаты, которые отправляли на сервер. Поговорили с командой и решили, что же нам нужно от хороших логов, давайте с вами об этом тоже поговорим.
Для начала нужно понять, в каком режиме была зарегистрирована координата, Это может быть либо background, когда приложение в фоне или убито, либо foreground, когда вы видите UI приложения.
Дальше нам нужно понять, как она была получена: напрямую от GPS, или от каких-то других провайдеров, о которых мы поговорим немножко позже, или система могла сама запушить нам координаты, если мы используем то или иное API (допустим, geofencing, visits API или significant location change API на iOS).
Дальше нужно залогировать все, что можно о координате: точность, высота, скорость, вектор движения, время получения вплоть до миллисекунд. Это тоже очень важно, зачастую координаты измеряют свою точность скачкообразно с разницей в несколько миллисекунд. И любая другая информация, которая облегчит вам жизнь: например, как пользователь двигался (прыгал, бегал, ехал на велосипеде, плыл на лодке), включен или выключен Wi-Fi и т.д.
Ну и, наконец, нам нужно понять, по какому принципу мы будем все эти координаты отправлять.
Если у вас простая бизнес-логика, то это будет просто по таймеру, допустим, каждые 30 минут. Иначе это могут быть какие-то другие условия: либо описанная вами бизнес-логика, либо приложение было убито и затем оживлено. Оно может быть убито out of memory killer, вы могли сами его убить, или оно могло просто закрашиться. Оживить его может пуш-нотификация или какой-то API. Раз уж вы умерли и оживились, то будьте добры зарегистрировать и отправить координату на сервер.
Ок, мы собрали эти координаты и отправили на сервер, но почему-то не получили ожидаемого результата: или не пересеклись, или не зачекинились где-то. Идем ногами к нашим разработчикам, спрашиваем, что же не так. Клиентские разработчики говорят, не знаем, давайте пойдем к серверным разработчикам. Идем к ним, они помедитировали на PHP-код, поселектили в базе, сказали в чем проблема. В общем, мы сходили к ним пару раз и очень быстро их этим утомили, поэтому они сделали нам на основе собираемых логов очень удобную веб-страничку, где видим все наши передвижения, наложенные на гугл-карту:
На ней удобно рассматривать координаты с увеличенным уровнем зума на большом мониторе, вместо того, чтобы делать это на девайсе. Это помогло нам найти объяснения всяким странным ситуациям, происходящим в реальной жизни, когда мы думали «мы здесь», система определила, что мы находимся в другом месте. Иногда это делаем мы сами по какой-то ошибке, а иногда так находили баги на сервере, когда он неправомерно те или иные координаты отфильтровывал. В этом инструменте удобно, что отметки на карте закодированы цветами, и они показывают, почему та или иная локация невалидная (слишком часто регистрировалась/отправлялась, точность у нее низкая, либо что-то с ней не так). В общем, логи — это сила, рекомендую.
Козя:
Мы поняли, что с хорошими логами можно доказать, что это реально баг, а не фича, или же она воспроизводится, и взять девелопераза… c поличным :) Давайте поговорим, как сэкономить 7 кг нервных клеток. Мы с Сашей любим экономить нервные клетки, поэтому такие большие и красивые, кто из нас большой, а кто красивый — решать вам.
Именно debug menu сэкономило нам дополнительно семь килограммов нервных клеток. На Android меню простое. А если вдруг вам нужна более подробная информация, можете установить инструмент GNSSLogger от Google и получить еще больше дополнительной информации о том, как работает спутниковая навигационная система, вплоть до значений интерференции атмосферы в данной точке пространства. Я не знаю, зачем вам это может быть необходимо в большинстве случаев, нам это не надо, поэтому мы сделали простейшее меню. Вы можете видеть все о текущей локации, посмотреть карту перемещений, того, как вы перемещались. Очень удобный инструмент в субботу с утра, чтобы понять, что вы делали в пятницу вечером! Также есть система логирования, где записаны логи, ну и какие-то дополнительные инструменты: например, переключить систему геолокации с фейковой на настоящую, отправить логи на компьютер для дальнейшего их изучения, очень удобно, очень просто.
На iOS меню поприкольнее, но это же iOS.
Хозя:
У нас оно немножко посложнее, и мы его делали в один заход, в отличие от Android, где делали итерациями. Потому что мы сразу знали, что на iOS все плохо, и нам нужна вся эта информация! Самая первая переключалка, которой мы особенно гордимся — это локальные уведомления о работе location manager.
То есть вы можете свернуть приложение, убить, залочить девайс, но как только что-то изменится, вы получаете уведомление. Не то что не надо заходить в debug-меню и смотреть логи, а даже приложение не нужно запускать: девайс автоматически включает экран, когда вам приходит уведомление, это очень удобно. Так же чуть ниже у нас есть два набора координат: это последняя известная локация, и последняя отправленная, тоже для нашего удобства.
А также есть вьюшка с Apple-картами, на которых мы строим наши трассы движения, по той же причине, что и объяснял Коля: соединяем две точки и смотрим, были ли мы там. На ней есть интересный пин, который показывает временной промежуток. Чтобы его увидеть, необходимо воспользоваться Visits API, которая доступна с iOS 8, то есть уже достаточно долго. С точки зрения системы это работает достаточно хитро, потому что система за нас определяет, зашли мы в какую-то точку или вышли. Мы зашли куда-то, и примерно через пять минут нахождения там система понимает: «ага, мы, наверное, куда-то зашли», посылает нашему приложению уведомление, что в такое-то время вы зашли в точку с такими координатами. После того, как мы вышли, тоже примерно через пять минут она посылает точно такое же уведомление про выход. Соответственно, мы знаем, что провели там, допустим, 45 минут. Для функционала «Пересечений» просто великолепно: вы сидите и пьете кофе, мимо вас проходит огромное количество людей, вы с ними пересекаетесь. Просто великолепная API, жаль, что она не появилась с самой первой версии нашего сервиса. Мы его делали еще под iOS 7.
Все наши координаты, которые мы записываем, закодированы цветами, чтобы можно было быстро глазами пробежаться и понять, как она была зарегистрирована: белым цветом координаты в foreground, серым — background, фиолетовым — visit.
Мобильный тестировщик, поэтому и мобильный, потому что мы все свое носим с собой. В большинстве случаев нам этого debug-меню было достаточно, но основная проблема мобильных девайсов — это наличие аккумулятора.
Козя:
И чем более энергоэффективно ваше приложение, тем дальше от розетки вы можете отойти. Напомню, это был 2014 год, было мало информации и о том, как тестировать энергопотребление, и о том, как правильно тестировать геолокационные сервисы.
Давайте поговорим об общих методах, которые мы нашли в первую очередь. Для начала мы воспользовались Power Meter. Это простейший девайс: с одной стороны он подключается к источнику энергии, с другой стороны подключается дата-кабель, к нему — ваш девайс, и показывает ток. А вот то, какой ток он показывает — это проблема.
Есть два случая. Первый: если ваш аккумулятор не заряжен, он показывает ток заряда, который потребляет ваш телефон, чтобы зарядить ваш аккумулятор. Это не совсем репрезентативные данные.
А если ваш телефон все же заряжен, то вы опять же не видите реального тока (за исключением Android, попозже расскажу). Потому что телефоны настроены таким образом, что если есть внешний источник энергии, то они выполняют еще синхронизацию, обновления приложений, а в последней версии Android еще и код компилируют за вас. Тоже нерепрезентативно. На андроиде вы можете отключить внешнее питание программно, тогда Power Meter будет, возможно, показывать верные данные. На iOS это невозможно.
Также существует специальный «метод Яндекса», о котором здесь, на Heisenbug, тоже есть доклад от парней из Яндекса. Но нам, к сожалению, этот метод не подошел, потому что мы не измеряем энергопотребление после каждого коммита, а двигаемся в разных режимах. Парни, простите, реально неудобно ходить на улицу с девайсом, у которого раскурочена задняя крышка, и подключена коробочка с Arduino, которая подключена к ноутбуку. Меня на улице, по меньшей мере, не поймут!
Давайте поговорим о методах измерений непосредственно на девайсах. Первым делом поговорим об Android, потому что он на букву А.
Самое первое, что можно сделать на Android — это зайти в настройки энергопотребления, и посмотреть, что вообще творится. Если вам жутко не повезет, то вы увидите ваше приложение в списке на одном из первых мест. Хотя, понятное дело, если вы постоянно пользуетесь вашим приложением, то оно появится в топе в любом случае, просто потому что вы им так много пользуетесь.
Зайдя в расширенную информацию энергопотребления на последних версиях Android, вы можете видеть очень много полезной информации: использование CPU в foreground, в background, использование датчиков (например, GPS), и т.д.
Почему здесь дополнительно есть Google Play Services? Одно и то же приложение на разных версиях Android будет иметь различное энергопотребление: до Android 8.0 ваше приложение при использовании Google Play Services вызывало энергопотребление этих «сервисов», а не ваше энергопотребление. К восьмой версии Google понял, что пользователи слишком много жаловались на «выжирающие батарейку Google Play Services» и сказал: «Хорошо, теперь любое энергопотребление, которые было вызвано вашим приложением, идет обратно к вам». И вы видите свое реальное энергопотребление, поэтому поставьте восьмерку и ужаснитесь или обрадуйтесь.
Следующий метод, который мы начали использовать — это Test Fairy, библиотека-sandbox, встраиваемая в ваше приложение и записывающая большое количество данных. Мы используем ее в случае с бета-пользователями, они получают за это всяческие плюшки вроде бесплатных кредитов, а мы получаем от них большое количество данных.
Одни из этих данных — это энергопотребление, но и здесь не все гладко. У пользователя сессия в основном 1-2 минуты, потом она закрывается, начинается новая, и изменение аккумулятора за этот период не такое уж интересное, оно вообще может равняться нулю (шкала там не в мАч, а в процентах, и на современных девайсах с аккумуляторами 3000+ мАч один процент довольно велик). Или же у пользователя может быть длинная сессия, как этот пользователь с 22-минутной сессией, но его телефон был подключен к источнику энергии, поэтому мы ничего не видели. Остальных пользователей, у которых реально происходит разряд, настолько мало, что данные просто не поддаются толковому анализу.
Следующий инструмент, который я начал использовать сразу же, как только он вышел — это Battery Historian. Спасибо компании Google, уникальный инструмент, является фактически «дактилоскопом» для определения, кто все-таки и когда жрал батарейку. Даже если вы не исследуете свое приложение, вы можете увидеть, какие другие приложение и почему ели батарейку.
Здесь видите, что я выбрал момент времени, кликнув на график, вижу, что наше приложение было активным 3 минуты. Вижу, какие сенсоры использовало, какие сервисы, и особенно это помогает при исследованиях энергопотребления: позволяет понять, геолокация ли жрет приложение. Бывает, что developer случайно создал infinite loop и забыл сделать из него выход. Всякое бывает.
Для того, чтобы дополнительно прикрыться с тыла, мы используем мониторинг. У нас очень сильная команда мониторинга, и помимо всех метрик, они по нашей просьбе еще мониторят энергопотребление наших пользователей, и после релиза мы можем видеть тренд и оперативно реагировать на него.
Система работает очень просто, мы два раза посылаем ивенты о заряде аккумулятора: один раз, когда приложение стартует, а второй раз, когда приложение сворачивается или убивается. Мы на основе этого строим тренды, очень удобно, очень полезно, и мы хорошо прикрыты. А на iOS все боль.
Хозя:
Как обычно, на iOS все классно для пользователей (не так легко выжрать батарейку, как на ранних версиях Android), но для инженеров большая печаль.
Мы начали с самого первого инструмента, то же самое: «Настройки» — «Аккумулятор». Инструмент в целом очень плохой, у него есть всего один плюс: показывает, сколько ваше приложение работает в бэкграунде. Для нас это важно, потому что мы собираем и отправляем геолокацию в том числе в фоновом режиме.
А дальше начинаются боль и страдания. Инструмент очень инерционен, обновляется примерно раз в час. Поэтому, если ваше приложение 5 минут работает нормально, а 55 жрет батарейку, как не в себя, вы этого не видите. А если вы захотели заресетить два девайса, поставить на них два разных билда и сравнить их по энергопотреблению, то мало того, что первый результат увидите через час, так если не запустите три или более приложения, вы вообще ничего не увидите, и еще раз отложите все на час.
Следующий инструмент — это Energy impact шкала в Xcode. Подключаетесь дебаггером к вашему приложению, нажимаете третью ячейку сверху и видите шкалу, которая изменяется в реальном времени: от зеленой зоны, где не потребляете энергии, до красной, где жрете, как не в себя.
Чуть ниже показано, почему потребляется: допустим, CPU загружен на 100%, или вы не даете системе заснуть, или все время ее будите, или забыли погасить GPS после того, как он не нужен. Но без разработчика с этим разобраться достаточно сложно: например, потому что при запуске вы будете жрать CPU потому что надо запустить приложение и прогрузить данные, у вас будет включен GPS, чтобы отправить локацию на сервер и получить людей рядом с вами, и еще будете скидывать кэш на диск. Нормально это или ненормально, черт его знает. Поэтому мы разработали сет кейсов и прогоняем с разработчиками после каждого большого рефакторинга.
Следующий инструмент — это настройки энергопотребления в вашем айфоне: заходите в «Settings — Developer — Instruments», включаете запись энергопотребления и работы с сетью. Работа с сетью опять нам пригодилась, потому что мы отсылаем эти координаты на сервер.
Но инструмент, опять же, не очень, потому что он пишет данные обо всей системе, между приложениями что-то сравнить тоже сложно — их вагон в списке. Данные об энергопотреблении показываются какими-то непонятными на первый взгляд дробями, а не миллиампер-часами, как на Android. Дроби, как ни странно, показывают сколько девайс будет жить с текущим энергопотреблением. Например, 1/17 значит, что в данный срез времени при текущем энергопотреблении девайс разрядится в ноль за 17 часов.
Для того, чтобы писать данные конкретно по вашему приложению, нужно подключать instruments именно к вашему приложению. Если вы будете ходить по улице с ноутбуком, шнурком и девайсом, вас могут не понять.
Вот такая печаль iOS, я надеюсь, в докладе ребят из Яндекса что-то классное будет, что с этим поможет. А вот у ребят на Android все классно — Battery Historian, графики, ребята прикрыты со всех сторон.
Хозя:
Мы поговорили о том, как измеряли энергопотребление, теперь давайте поговорим о том, как принимали те или иные решения для оптимизации. К счастью, наши разработчики классные и читают документацию, но если где-то что-то пропустили, команда тестирования идет на помощь. В большинстве случаев мы проверяли ту или иную теорию, и она подтверждалась либо опровергалась. Открываем документацию по Location Manager в iOS и видим, что первым делом Apple рекомендует вам снизить настройку точности при определении местоположения, и мы ее снизили до 100 метров.
В любом случае система будет стараться вам дать координаты как можно точнее. Как минимум потому что у вас на девайсе, скорее всего, есть другое приложение, которое использует геолокацию. То есть вы можете ее получить «за чужой счет»: если другое приложение получило локацию, вы можете ее использовать. Например, пять минут назад другое приложение получило геолокацию, в принципе, иногда достаточно. «Расслабление» настроек позволяет Apple сэкономить на энергопотреблении.
Но, как обычно, сложно быть сразу умным и красивым, причем не только на iOS, но и на Android. Например, вы долго были на парковке либо ехали на поезде с большой скоростью, у вас была низкая точность. Вы запускаете приложение, и у вас есть два способа получения координат: либо быстро, но не точные координаты (вплоть до 1000 с чем-то метров), либо долго и точно. Но, как Коля говорил раньше, «долго и точно» вообще не гарантирует ее получение, если вы в подвале, то можете ждать 15 минут и не получить (вы, например, в подвале). Поэтому мы выбрали путь «быстро, но не точно», и разработали механизм изучения координат.
Это отвечает на вопрос, зачем нам нужна была селфи-палка во время тестирования. Берем девайс, ноутбук, шнурок, подключаемся к дебаггеру, спускаемся на парковку, лочим девайс, ждем две минуты, чтобы система полностью заснула. Дальше заходим в лифт, поднимаемся на четвертый этаж, быстро бежим к окну, по пути разлочивая девайс, выставляем девайс на селфи-палке за окошечко и видим, как система одним или несколькими шагами уточняет местоположение. Это, конечно, весело и интересно, к счастью, это покрыли unit-тестами, и ни один телефон не пострадал.
В общем и целом, механизм уточнения работает просто: в течении 20 секунд (после запуска приложения либо после того, как мы вывели его из фона) мы слушаем координаты от системы с возрастающей точностью. 20 секунд — это таймаут, выбранный эмпирически после экспериментов на подвалах и парковках :) Через 20 секунд мы отправляем более точные координаты, если они есть, а если нет, то мы потихоньку умираем и все.
Дальше мы решили использовать Significant location change API. Вместо того, чтобы будить приложение и включать GPS (что очень неэкономично), вы подписываетесь на API, и система сама пушит вам уведомления о значительном изменении координат, вам их надо только сохранять в базу и отправлять. Очень классно.
Что именно означает «значительно», «significant»? Это неизвестная величина, она зависит от скорости движения, режима движения, энергопотребления, режима сохранения энергии, очень много неизвестных. В общем и целом, при ходьбе пешком это 750 метров, при езде на автомобиле с небольшой скоростью это от 750 метров до нескольких километров. По энергопотреблению это вам практически ничего не стоит, надо только записать координаты либо сразу их отправить. Но, как обычно, у Apple все опять плохо.
Мы не можем сделать сервис, который работает только с координатами и перекачивает данные в приложение, как на Android. А значит, если нас прибило и потом оживило, то нам нужно оживлять все приложение. Чтобы жрать батарейку чуть-чуть, а не очень сильно, нам приходится инициализировать только части нашего приложения. То есть мы инициализируем систему работы с сервером и систему по работе с локацией: мы не грузим encounters (наш первый и основной экран), не инициализируем какие-то скрины, и так далее. Иначе это была бы беда.
Также мы используем Visits API. О нем я уже рассказывал раньше, но наша первая версия работала с API iOS 7, поэтому изначально его не было.
Также во время сбора и отправки координат и выполнения всяких задач Apple рекомендует дать послабление времени, плюс-минус несколько секунд, чтобы система сформировала пачку задач, проснулась, выполнила всю пачку задач и обратно заснула. Иначе она будет просыпаться под каждую задачку и жрать вам батарейку.
Ну и последнее: мы придушили немного таймаут при работе с сетью. По умолчанию на iOS это 120 секунд, как и время работы NSurlsession в фоне, которую мы используем при отправке координат на сервер. Это очень много, мы это придушили, если мне не изменяет память, до 30 секунд. То есть если у нас плохая сеть, мы чуть-чуть подолбили сервер и не получили ответа, то умерли, и перезапланировали отправку, допустим, на 5 минут в будущее. Если это делается 120 секунд, мы, опять же, начинаем выедать батарейку. Особенно, если у вас нет Wi-Fi, а есть 3G: работа с сотовой сетью менее энергоэффективна
Давайте теперь поговорим про Android.
Козя:
На Android мы сразу же после появления Fused Location Provider начали им пользоваться. Его характеризует низкое энергопотребление, потому что библиотека сама за вас решает, какой источник геоданных выбирать. Не всегда GPS является самым оптимальным и быстрым способом нахождения вашей геопозиции.
Второе достоинство — это возможность получения геолокации за чужой счет. Как говорил Саша, они не могут создать сервис на iOS, а мы на Android сервис создать можем. Что мы и сделали, и просто получаем локацию за чужой счет, подписавшись: если какому-то другому приложению нужна локация, например, Яндекс.Навигатору, мы получим эту локацию себе, просто сохраним в базу и потом отправим, а все энергопотребление уйдет на навигатор.
Также можно задать нужную точность, чтобы ваш сервис не получал большое количество координат. Потому что, как мы вчера проверили в московском метро, точность бывает и до пяти километров. Можно задать нужную точность получения, например, «нам нужны координаты с точностью 100 метров и точнее», и остальные будут отфильтровываться системой, очень удобно. Также есть разные стратегии: получение по таймеру, получение в случае запуска какого-то сервиса, пользователь вошел в какое-то место. Стратегий много, поэтому читайте документацию и найдете то, что вам лучше всего подойдет.
Тут я бы закончил говорить про наши оптимизации, если бы не там проблема, что Fused Location Provider закрывает лишь 90% наших потребностей. А ещё 9% закрывает Legacy Location Provider — это старый провайдер, который был в Android с давних времен. Им можно пользоваться, но он не такой энергоэффективный и нужен для старых девайсов, которые не поддерживают новые типы Google Play Services, или же для девайсов без Google Play Services, например, от неизвестной китайской компании Xiaomi.
Остальной процент данных закрывает самописная система, которая называется Aggressive Location Provider. Она основывается на Legacy Location Provider, и нужна по крайней мере для двух случаев:
Во-первых, бывает так, что Fused Location Provider вообще не вернул удовлетворяющие нас координаты (например, ваше приложение является единственным приложением в системе, которое обрабатывает геоданные, а вы решили подписаться за чужой счет и ничего не получили). А наши продакт-менеджеры хотели от нас большого количества координат, и мы так перестраховались.
Второй случай. Google Play Services — это приложение, которое пишется людьми, так что оно тоже может «умереть», может неправильно перезапуститься после обновления, и может произойти много других вещей, поэтому дополнительная подстраховка — это всегда важно.
При этом у Aggressive Location Provider очень трепетное отношение к заряду аккумулятора пользователя. Например, в случае падения заряда меньше 20%, переключения телефона в режим полета или ручного включения режима энергосбережения, мы перестаем использовать Aggressive Location Provider и вообще трогать телефон в этом плане. Чтобы уважать пользователя и его настройки.
Кроме того, есть Activity Recognition API в составе Google Play Services — удобная система паттернов активности пользователя. Существует 4 основных паттерна: хождение, бег, велосипед и нахождение в транспорте (будь то общественный или свой).
Кроме того, есть дополнительные паттерны, например, очень удобный still. Например, вы взяли свой девайс, зашли в какой-нибудь бар, положили девайс на стол, чтобы общаться с другими людьми, и ваш телефон лежит неподвижно. Паттерн still сработал, мы получили эту информацию и запоминаем местоположение недалеко от того момента, когда мы получили still, или же просто пытаемся уточнить местоположение сейчас. После чего мы забываем о вопросе местоположения девайса до того момента, как пользователь не взял телефон, чтобы выйти из бара, потому что он уже наобщался. И мы поймем, что с такого-то по такое-то время пользователь был неподвижен в этой точке.
Тут все хорошо, за исключением некоторых случаев: например, вы едете на поезде Санкт-Петербург-Москва, положили телефон на полку, у поезда идеальная подвеска, железная дорога прямая, ваш телефон оказывается в режиме still. Вы приезжаете в Москву, хотите посмотреть, пересеклись ли вы с той девушкой в Вышнем Волочке или нет, но, к сожалению, вы не пересечетесь, потому что мы получили still, и, возможно, все время думали, что вы находились на Московском вокзале Санкт-Петербурга. Поэтому нужно все же перестраховываться и слушать систему: если локация все-таки меняется, то инвалидировать паттерн, потому что паттерн — это лишь вероятность.
Итак, вы обкатали все, что у вас есть в ваших лабораторных условиях, поняли, что это как-то работает, но все равно это сферический конь в вакууме, потому что в реальных условиях могут быть те или иные ситуации, вам нужно начинать их понимать. Для этого вам придется выходить «в поле».
Козя:
И для того, чтобы выходить в поле, вам нужно понять, что с собой брать. Нужно брать реальные девайсы, с различными версиями ОС, включенным/выключенным Wi-Fi, с различными настройками энергосбережения, с сим-картами и без них. Хочу заметить, что две различные сим-карты могут иметь различное энергопотребление: например, одни поддерживают 4G, а другие нет. Бывает так, что даже две сим-карты, которые поддерживают одинаковые частоты, имеют различное энергопотребление, потому что у них разные прошивки. Мы с Сашей столкнулись с этим, пользуясь сим-картами Vodafone из разных партий.
Дальше вам нужно понять вашего пользователя. Потому что, чтобы найти баги пользователя, нужно быть, как пользователь, нужно двигаться, как пользователь, делать вещи, которые делает пользователь. Ну и быть пользователем вашего приложения, в конце-то концов, dogfooding никто не отменял. И вот чем мы занимались.
Хозя:
Первым делом мы решили выйти из офиса и немного прогуляться по окрестностям. Чем это так удобно? Да тем, что очень сильно гуляет точность определения местоположения из-за различной плотности застройки, различной плотности сетей Wi-Fi и сотовых сетей. Лондон очень неравномерный.
Также «рваный» темп хождения позволяет проверить интервалы отправки. Вы не ходите с одной скоростью: кто-то перед вами затупил, вы кого-то обогнали, постояли на пешеходном переходе, спустились в подземный переход и так далее. Конкретно в нашем случае это даже позволило найти нам баг. Если во время формирования пачки координат перед отсылкой получали координаты, они добавлялись как в пачку на отправку, так и в кэш. Соответственно, в редких случаях мы дублировали эти координаты. Воспроизвели, если по-честному, случайно, но кейс интересный.
Также очень удобно тестировать «визиты» на iOS. Напомню, что расстояние между двумя точками signification change — это 750 метров, и «визиты» присылаются с задержкой спустя плюс-минус 5 минут. Почему это удобно: расстояние между пабами в центре Лондона значительно меньше этих 750 метров.
Поэтому вы заходите в паб, пьете пинточку, выходите, за 5 минут доходите до следующего паба, и тут может что-то не то произойти. Конкретно в случае iOS мы зажевывали либо выход из предыдущего заведения, либо вход в следующее, если они по времени оказывались очень близко. Помогло нам переписывание всего этого дела на Swift, потому что static analyzer там работает значительно лучше и помог нам определить что мы использовали неправильную константу и выражение всегда ложно.
В общем и целом, тестировать легко и приятно: пьете пинточку (обычно я пил пинточку с Козей), пересекаетесь, получаете push, открываете его, смотрите. Если место правильное, и/или мы уже натестировались — надо идти домой.
Также хождение по всяческим заведениям позволило найти потенциальный баг, который мог развалить всю нашу систему обучения чекинов. В Лондоне, помимо пабов, очень много всяческих заведений на квадратный метр. Скажем так, на площади 100-200 квадратных метров может быть 4-5 кафешек. А точность у нас обычно 10-30 метров. Поэтому определить, что вы в конкретной кафешке, очень сложно. И мы поступаем достаточно нетривиально: заходим в кафешку, получаем событие входа, забираем подключенную точку Wi-Fi и ее MAC-адрес (если, конечно, она есть), и отправляем на сервер. То есть если пользователи постоянно заходят в эту точку, у них тот же самый Wi-Fi, то с большой долей вероятности вы находитесь-таки в этом месте.
Но, как оказалось, в Лондоне еще есть открытые сети Wi-Fi, и за три минуты я могу дойти до следующего заведения и уже находиться в нем, и опять захватить точку доступа и отправить на сервер. Мало того, что сервер обалдел, от того что у него две различные Wi-Fi-сети на событие входа и выхода, так еще и физически между ними расстояние может быть 300-400 метров. В зависимости от того, насколько быстро вы ходите, это надо учитывать, поэтому волевым решением мы отключили запись имени точки доступа на событие выхода из места.
Дальше мы решили покататься на общественном транспорте. Первым делом — на автобусах, потому что центр Лондона очень забит, а автобусы ездят с низкой средней скоростью. Также это позволило проверить и оттюнить определение характера движения: едете вы, идете и т.д. Такое определение — это вероятность, то есть при езде на автобусе, условно, с вероятностью 90% вы будете определяться едущим на автобусе, а с вероятностью 10%, допустим, на велосипеде. В некоторых случаях вам соответствующие веса надо будет подтюнить.
Также при езде на автобусе мы поймали забавный серверный баг. При остановке на пешеходном переходе либо на светофоре мы иногда получали location. Так как сервер не знал, через какое мы получим следующую локацию и что мы до этого тормозили, то пытался чекинить нас в ближайшем заведении к автобусной остановке. Решили мы это проблему просто: мы добавили определение скорости (в метрах в секунду), и если скорость не нулевая, то чекинить нас в этом заведении не надо.
Дальше мы решили спуститься в лондонское метро. Оно очень старое, там нет сотовой сети, не ловит GPS, поэтому наименее читерский способ определения местоположения — по Wi-Fi: заходите в вагон, доезжаете до следующей станции, у вас автоматически подключается Wi-Fi, определилось местоположение, тоже очень классно и удобно.
Дальше мы решили покататься на автомобиле и на такси. Чем это удобно: операционная система пытается тюнить энергопотребление, если вы двигаетесь с большой скоростью, и у вас не включен навигатор. Поэтому при езде со скоростью 20-30 км/ч это 750 метров в фоновом режиме, а при езде 110 км/ч — уже 2-4 км, а если вы едете на скоростном поезде до аэропорта (у нас в Лондоне ездят примерно 250 км/ч), и у вас не так много сотовых вышек, это уже 4-11 км в зависимости от плотности вышек, потому что быстродвижущиеся объекты GPS зафиксировать достаточно сложно, и в поезде много металла, который не способствует точности определения местоположения.
Также в зависимости от скорости движения, если вы используете Geofencing API, необходимо правильно выставлять радиус. Geofencing работает достаточно просто: вы заходите в точку, ставите вокруг себя радиус, по выходу из него делаете какое-то действие (допустим, отправляете пачку координат). Либо, наоборот, вы заходите в определенное место. Допустим, заходите в McDonalds, вас идентифицируют и шлют push «сегодня для вас бургер в два раза дешевле». Если вы двигаетесь быстро, то необходимо поставить радиус побольше. Иначе вы будете высаживать аккумулятор, будете часто выходить из этого радиуса, или, наоборот не будете из него выходить, если точность координат его превышает.
Козя:
Помимо этого, в Android 7+ может произойти другой прикол. У вас есть телефон, вы садитесь в машину, кладете его на пассажирское сиденье, едете из точки А в точку Б. Доехали, хотите посмотреть, сколько локаций получил ваш телефон, смотрите, а их нет вообще. С чем это связано? Google решил сделать пользователям хорошо, а разработчикам плохо, и ввел так называемый doze, режим сна. Мало того, что когда телефон не используется, он «спит», так еще и с версии Android 7.1 Google добавил агрессивный doze. Чем он плох: ваш телефон начинает быстрее анализировать ситуацию, понимать, что он не востребован, как раз в случае, когда вы его кинули на пассажирское кресло и едете в точку Б, и в итоге не получает координаты. Почитав документацию, обнаружили, что можно получать координаты хотя бы четыре раза в час — с паршивой овцы хоть шерсти клок.
Мы поняли, что наш конь уже не сферический, а реальный. Давайте теперь поговорим о самом страшном.
Козя:
Первая страшная вещь — то, что девайсы могут ломаться и падать, поэтому запасайтесь хорошими чехлами перед любым полевым выходом.
А второе — это регрессия.
Хозя:
После того, как мы проверили багфиксы, основную функциональность, первым делом мы задаемся вопросом: не просели ли мы по количеству собранных и отосланных координат? Кэп намекает, что надо взять два девайса, поставить на них различные сборки и прогуляться с ними, сравнить координаты. Но как бы не так. Коля раньше говорил про сим-карты с различным энергопотреблением, а мы столкнулись с еще одним интересным способом доказать, что девайсы очень сложно поместить в одинаковые условия.
У меня был один тестовый девайс в правом кармане, а другой — в рюкзаке, потому что в задний карман опасно класть, могут вытащить. Как оказалось, при ходьбе девайс, который был в кармане, больше двигается, чаще просыпается и собирает больше координат. Придя на работу, я увидел, что девайс, который находился в рюкзаке, собрал их раза в полтора меньше, и различные билды приложения не имели к этому отношения. Поэтому старайтесь помещать девайсы в максимально похожие условия.
Также мы рекомендуем вам долговременную проверку сервиса в фоне, потому что в современных девайсах омерзительно большое количество оперативной памяти. Например, есть модификации OnePlus 5 на 6 и 8 гигабайт RAM, в таком случае ваше приложение в фоне будет жить очень долго, а раз оно живет, то пусть и работает правильно. Мы обычно оставляем приложение, подключенное к дебаггеру и в режиме симуляции движения на ночь или на выходные.
Но круче всех нам с тестированием помог Коля, когда во время релиза этой функциональности ему пришлось перегонять автомобиль из Москвы в Лондон. Мы ему выдали несколько коробок тестовых девайсов, он за два дня и 3000 километров собрал нам огромное количество координат, пересекся с юзерами, у которых была выключена фича (и сам с собой в том числе), собрал нам гигабайты логов, помог найти несколько багов, которые поправили перед запуском.
Давайте теперь поговорим о багах, все-таки у нас конференция по тестированию.
Козя:
После релиза фичи нам начали приходить координаты из прошлого и из будущего. Чем вызвана проблема: наши пользователи двигаются и могут пересекать часовые пояса, уходить в прошлое и будущее относительно того timestamp, в котором были получены первоначальные координаты.
Помимо багов девайсов и прошивок в определении timestamp при пересечении часовых поясов, подобные ошибки оказываются вызваны и другими багами, но решить это можно просто. У девайса всегда есть время, которое больше нуля — это uptime, время с момента запуска. Мы его складываем при получении координат, и уже потом, когда эту пачку координат нужно отправить на сервер, отправляем с uptime-временем. В принципе, это закрывает большинство проблем.
Вторая проблема — это люди, которые начинают телепортироваться. Помимо вещей, о которых я ранее говорил (пользователь резко меняет координаты, чтобы докучать другим пользователям, или же угнали аккаунт), вполне реальный пользователь тоже начинает телепортироваться в пространстве. С чем это связано: в первую очередь, с тем, что при уточнении координат, точка может гулять. Уточнение координат и смещение центра может происходить с очень большой скоростью. И мы просто ограничили максимально возможную скорость перемещения наших пользователей скоростью пассажирского лайнера, больше пока что нереально. Это решило 99.9% проблем, за некоторыми интересными исключениями.
Хозя:
Напомню: если у вас не ловит либо выключен GPS, локация берется от включенного Wi-Fi либо базовой станции. Мы столкнулись в природе как минимум с двумя кейсами ошибок. Первый — когда отмечали 10 лет компании Badoo в красивом загородном доме с очень толстыми стенами и потолком, соответственно, у нас не ловился GPS. Наши доблестные админы притарабанили точки доступа из лондонского офиса, и при запуске приложений карт и нашего приложения получалось, что мы находимся именно в лондонском офисе. К счастью, современные точки доступа умеют обновлять свои местоположения довольно быстро, от нескольких минут до нескольких дней. У нас все это дело пофиксилось через пару-тройку часов.
А те, кто живут в Москве, знают более популярную историю: если вы подходите к Кремлю, то вас может «телепортировать» во Внуково, и с нами это тоже случалось. Погуглив, мы обнаружили, что подменяют координаты GPS/ГЛОНАСС и выставляют координаты Cell ID во Внуково. Ребятам из Яндекс.Такси приходилось даже делать хак, чтобы более-менее нормально подвозить или забирать людей оттуда.
Также некоторых юзеров телепортировало в Китай и Бразилию. Как оказалось, в Бразилию телепортировало в основном с девайсов Blackberry: оказывается, когда у них что-то случалось с подсистемой работы GPS, их телепортировало на место сборки устройства в Бразилию. А в Китай перебрасывались китайфоны, у которых что-то пошло не так.
Также перебрасывало между двумя точками некоторые девайсы на iOS. Если не изменяет память, до версии iOS 9.2 у них был очень противный баг: при получении локации в фоне система с разницей в 10-15 миллисекунд допушивала очень старую локацию, допустим, полученную 6-8 часов назад. Вы идете вперед, потом прыгаете назад, потом идете вперед. Ради этого нам пришлось писать фильтрацию устаревших координат: как на клиенте, так и делать костыли на сервере, все-таки на клиенте не всегда возможно это сделать. Сервер просто сглаживает это все дело.
Последний баг, который лично мне попил немало крови: если вы симулируете геолокацию на реальном девайсе, и в этот момент «поплохело» Xcode, или вы выдернули шнурок во время сессии дебага, девайс замрет в последней известной ему геолокации. Курьезность ситуации в моем случае состояла в том, что я перед выходом домой симулировал точные координаты нашего офиса, взял этот девайс домой, а потом вернулся и с удивлением увидел, что он не получил координаты ни разу, в итоге это стоило нескольких человеко-часов — моих и разработчика.
Мы все рассказали, что хотели, давайте просуммируем.
Козя:
Самое первое, что мы поняли: без хорошего инструментария, будь то IDE, логи или дополнительные приложения, тестирование геолокационных сервисов будет создавать больше информационного шума, чем приносить реальной пользы.
Необходимость полевых выходов при тестировании геосервисов очевидна, но проблема в том, что даже выйдя в поле, вы не найдете все баги. Мы описали лишь некоторые подводные камни, у вас их может быть намного больше, или вообще не быть, в зависимости от того, как вы этим занимаетесь.
Все баги, найденные вами, желательно классифицировать и каким-то образом отмечать. Это могут быть баги вашей функциональности, баги API, непосредственно самого девайса или же геолокации, как в случае с перебросом во Внуково. Эти баги нужно иметь в виду, чтобы в случае нахождения, сразу быстренько говорить: это баг класса «геолокация», и мы его фиксить не будем, потому что не имеет смысла.
Тестировщики являются связующим звеном между пользователем и бизнесом. Понятное дело, что бизнес от нас хочет, чтобы было много координат, а пользователи не очень любят, когда их аккумулятор резко садится. Именно из-за этого нужно задумываться об измерениях энергопотребления как можно раньше. Но при этом важно и не переоптимизировать на очень ранних этапах разработки, потому что потом будет сложнее как тестировать, так и разрабатывать.
И самый главный вывод, который мы можем сделать сегодня на этой конференции: плотность пабов в СНГ намного меньше плотности пабов в Лондоне, и, если вам вдруг понадобилось с точностью протестировать ваши геолокационные сервисы, прогуляться по достопримечательностям, приходите к нам, мы с удовольствием вам поможем. Спасибо!
Ссылки по теме:
Мы решили, что аудитории Хабра он тоже может быть интересен, и выкладываем его сразу в двух версиях: для любителей посмотреть видеозапись, а для любителей читать под катом текстовая версия.
Вступление
Александр Хозя:
Давайте сначала познакомимся. Меня зовут Александр Хозя, в компании все называют по фамилии «Хозя», я к этому привык, можете тоже ко мне так обращаться. Я заведую всем ручным мобильным тестированием в компании Badoo, не люблю все мобильные операционные системы примерно одинаково, и сегодня буду говорить про iOS.
Николай Козлов:
Меня в компании по фамилии зовут «Козя», я тоже к этому привык. Обожаю гаджеты, особенно на операционной системе Android и вообще Unix-подобные. Не люблю iOS: имею Apple Watch и iPhone только чтобы понимать, насколько ненавижу их хороший сервис и качество обслуживания.
Немного о нас. Наверное, вы уже знаете, что Badoo — это сервис для поиска новых знакомств. У нас более 360 миллионов пользователей (из них 60 миллионов активных в месяц), и порядка 300 000 регистраций в день. Они генерируют 350 миллионов сообщений в день.
Что касается непосредственно нашего доклада. Чтобы вы понимали объем данных, который приходится обрабатывать нашим бедным серверам: наши пользователи в день генерируют порядка двух миллиардов координат. Эти два миллиарда генерируют около 10 миллионов «пересечений» — о том, что такое пересечения, расскажем чуть-чуть позже.
При этом все, что мы описываем далее, возможно только с тестовыми пользователями. Доступа к данным реального пользователя у нас нет, за исключением случая проверки какой-то аномалии или бага, и даже в этом случае нужно разрешение самого пользователя на данное действие.
Так вот, о чем сегодня мы поговорим:
- Чем полезна геолокация
- Об инструментах, которые позволяют сохранить семь килограммов нервных клеток (как видите по мне, экономятся хорошо)
- Об энергопотреблении при использовании геолокации и его оптимизации
- О том, почему необходимо работать в поле и выходить туда
- Ну и поскольку конференция о тестировании, конечно же, поговорим о багах
Чем полезна геолокация
Давайте для начала вспомним, что вообще такое геолокация, с чем ее едят, и как она работает в современных девайсах.
Исторически она появилась в iOS с релизом версии 2.0 в 2008-м, и тогда ваш телефон научился «вычислять по IP». Проблема была в то, что Geo IP дает низкую точность: в лучшем случае это будет улица, а в случае с мобильным девайсом обычно страна, потому что IP-адреса в большинстве случаев плавающие (у оператора в каждом регионе свой диапазон адресов, который зачастую никак не привязан географически).
В дальнейшем инженеры решили воспользоваться так называемым Cell ID. Принцип работы достаточно прост: мы знаем местоположение базовых точек в пространстве, и зная уровень сигнала от этих точек, можем примерно определить расстояние до них. Дальше рисуем большое количество кругляшков, и где-то в области наложения всех окружностей оказывается пользователь. Точность уже возросла: в небольших городах это 1000 метров, а в городах вроде Москвы, где базовых станций намного больше — это 60 метров. А при использовании Wi-Fi, Bluetooth и других beacon можно повысить точность до 10 метров, что очень удобно: не надо использовать следующую систему, которая называется GNSS, или глобальная навигационная спутниковая система.
Почему я говорю не «GPS»? Потому что на рынке навигационных систем существует несколько игроков. Основные — это GPS, GLONASS, китайская BeiDou и европейская Galileo. Кроме того, существуют две региональные навигационные системы — индийская IRNSS и японская QZSS («Квази-зенитная навигационная система»). Почему систем так много? Все системы двойного назначения, при необходимости в определенных случаях можно их отключить. Также некоторые системы нужны, чтобы уточнять местоположение, потому что в Индии и Японии есть известное смещение спутников GPS, которое нужно все время высчитывать, это лишняя головная боль. Японцы любят точность, и после введения QZSS достаточно всего лишь двух спутников, чтобы точность составила в худшем случае 10 сантиметров, а в лучшем случае один сантиметр.
При этом главная проблема всех навигационных систем — это холодный старт. У девайса, который только что был выпущен с завода и еще ни разу не получал геолокацию, при самом первом запуске холодный старт без A-GPS составит 15 минут: 12 с половиной минут он будет качать атлас звездного неба, и еще две с половиной минуты уйдут, чтобы получить сигналы со спутников. Это большая проблема, и поэтому придумали систему A-GPS: используя Geo IP и Cell ID, телефон быстренько определяет примерное местоположение и посылает это на специальный сервер, который отдает атлас. А через 2-3 минуты (в большинстве случаев даже меньше) телефон быстро находит спутники, и показывает вам, где вы находитесь, очень удобно.
Теперь давайте поговорим, для чего вообще нужна геолокация. Прежде всего — для персонализации контента.
Если ваш продукт — система навигации, и вы не используете геолокацию, скорее всего, пользователи его использовать не будут. Если вы делаете какое-то рекламное приложение, тоже возможна персонализация: вы проходите мимо какого-то магазина, телефон это понял, и срабатывает push-уведомление, что именно сейчас в этом магазине для вас скидка 50%. В дейтинге геолокация тоже очень важна. Наши пользователи хотят видеть тех, кто находится в их городе, а желательно вообще как можно ближе. И не хотят видеть пользователей из других стран. При помощи геолокации мы решаем эту и много других задач.
Все улучшения, связанные с геолокацией, мы разрабатывали для сервиса «Пересечения», о котором Саша расскажет чуть позже. Я скажу лишь, чтобы было понятно, как это должно работать с точки зрения пользователей, логики. Но было совершенно непонятно, как получать как можно большее количество координат и геоданных при как можно меньшем энергопотреблении. Это был 2014 год, было много информации о том, как это все реализовывать на стороне клиента, но абсолютно не было информации о том, как это нужно тестировать. К сожалению, все приходилось находить самому, и самому создавать документацию с нуля. А теперь давайте поговорим, где и как мы пользуемся геолокацией.
Хозя:
Самый первый наш главный экран — это знакомства, где пользователя голосуют друг за друга. Как Коля уже говорил ранее, значительно интересней находить людей и общаться, когда они находятся рядом с вами, поэтому геолокация — это один из самых главных весов, по которому наш сервер выдает пользователей друг другу.
У нашего следующего экрана говорящее название «Люди рядом», где в самой первой секции вы видите людей, которые находятся максимально близко к вам. Если, конечно, вы дали нам доступ к нашим сервисам геолокации. Если не дали, то мы вас попросим ввести хотя бы город. Открываете профили пользователей и видите, что они находятся рядом с вами: допустим, Алена была на расстоянии 300 метров от нас.
На этом же экране мы как раз показываем пересечения, и настало время рассказать, как же это все работает. В теории не очень сложно: вы двигались и в определенный момент траектории движения вас и других пользователей либо пересеклись в конкретной точке, либо вы были максимально близко друг от друга (например в 20 метрах). Если вы пересеклись с одним пользователем, то мы генерируем персонализированный push. Проверяем, общались ли вы с этим пользователем, допустим, вы его лайкнули или переписывались, он вас добавил в избранное, и т.д. Отправляем персонализированный push, можно открыть его профиль, увидеть, что пересеклись примерно в таком-то местоположении (примерно для того, чтобы избавиться от всяких злобных редисок, которые захотят вас встретить в подворотне). Если вы пересеклись сразу с 3-4 людьми, мы вас приземляем на экран «люди рядом», и пользователи, с которыми вы пересеклись, помечены там специальной галочкой.
Также геолокацией можно поделиться в чате либо запросить ее, допустим, чтобы пользователь подошел к вам: вы находитесь в какой-то кафешке, отправили геолокацию, очень удобно.
А также в одном из наших побочных продуктов геолокация используется для чекинов. В принципе, плюс-минус Swarm, но про дейтинг. Допустим, вы ходите в один и тот же стейк-хаус, и вам интересно, кто еще туда ходит, чтобы пообщаться о стейках. Либо вы пришли в клуб, запустили приложение и видите, что в данный момент в клубе 24 человека. Как показывают наши данные, нахождение общего места повышает шанс получения сообщения примерно на 40%, это очень много. Также мы используем геолокацию в антиспаме.
Козя:
В первую очередь, мы затрудняем триангуляцию нашими пользователями других пользователей. Дальше мы, используя геолокацию, можем определить, что пользователей резко сменил свое местоположение, и тут может быть два случая. Либо сработал антиспам, пользователь решил переместиться в другую страну, и докучать других пользователей, либо у пользователя угнали аккаунт в хакеры из другой страны. Мы в таких случаях принимаем меры.
Помимо этого, для сервиса пересечений мы разработали так называемый «Режим таксиста». Люди, которые постоянно двигаются по городу с включенным навигатором, генерируют очень много точных геоданных. Понятное дело, что у них будет много пересечений. Чтобы эти пользователи не примелькались и не докучали другим пользователям, у них пересечения генерируются по специальному алгоритмам с более жестокой фильтрацией.
Мы поговорили, чем хороша геолокация, где мы ее используем, давайте поговорим о другой проблеме, а именно проблеме сбора геоданных.
Сбор геоданных
Это временной график, и от момента старта вашего приложения до момента получения геолокации с заданной точностью может пройти время. Чтобы получать геолокацию быстрее, придется дополнительно использовать неэкономичные с точки зрения аккумулятора датчики — барометр, гироскоп и т.д. Но даже при использовании всех возможных датчиков, которые есть на девайсе, нет гарантии получения точности заданных координат.
Давайте почитаем определение точности непосредственно в документации Google: «Точность — это радиус вокруг точки, внутри которого с вероятностью 68% находится пользователь».
Или, проще говоря, с вероятностью 68% мы находимся прямо сейчас где-то здесь.
А можем и не находиться. Как вы видите, пришло две точки, и расстояние между ними намного меньше, чем точность, которую они выдают. С такими геоданными тоже необходимо уметь работать.
Получение точных геоданных зависит от времени, они могут не прийти вообще, это нужно уметь обрабатывать. Давайте поговорим, как протестировать сборку и отсылку локаций, не выходя из офиса, на самых ранних этапах: когда нужно проверить, что ваша система вообще умеет хотя бы как-то принимать геолокацию.
Для этого разумно использовать простейшие доступные средства, например, эмулятор Android. В режиме эмуляции локации содержит простейшие вещи, такие как эмуляции самой локации, и загрузка GPX-маршрута, о которой Саша попозже расскажет.
Любопытно, что дефолтная локация Android-эмулятора — деревня Далвик в Исландии. Dalvik — это виртуальная машина в Android до версии 5.0.
С другой стороны, на iOS почему-то, я сам не понимаю почему, симулятор намного богаче.
Хозя:
Да, действительно так. Обычно Apple очень дружественен к пользователям, но у инженеров вызывает огромную попаболь. Однако в этом случае в Apple подумали о нас, и нам доступны целых 3 варианта движения: пробежка, поездка на велосипеде и езда по трассе.
Удобно это тем, что система возвращает нам все необходимые данные о самой координате, скорость, вектор движения, горизонтальную и вертикальную скорость, а в некоторых случаях даже этаж. Очень удобно для тестирования геолокации, не выходя из офиса.
Но иногда, если вы свернете приложение в бэкграунд, система не будет присылать вам координат вообще. Это баг либо Xcode, либо симулятора, либо самой macOS. Чтобы это победить, нужно будет либо убить Xcode, либо симулятор, а если ничего из этого не помогло, то перезагрузиться. Но если вы запустили симулятор и у вас все работало, а потом после каких-то манипуляций перестало, скорее всего, это все-таки баг в вашем приложении.
Следующее, что мы используем — наша любимая среда разработки Xcode. Подключаемся дебаггером либо к симулятору, либо к реальному девайсу (это важно, немногие знают, что на реальном iOS-девайсе можно симулировать геолокацию), нажимаем на синюю стрелку, либо в меню выбираем Debug > Simulate locations, и видим выпадающий список с точками, которая Apple добавила — Москва, Лондон и т.д. Но нас интересует кнопка «Add GPX File to Workplace» в самом низу, которая позволяет добавить GPX маршрут.
Чтобы его сгенерировать, я рекомендую пользоваться Maps to GPX converter. На вход он принимает трассу из Google Maps — как полную URL, так и сокращенную. На выходе генерирует вам GPX-файл: на самом деле, это просто подмножество XML со временем и точкой в пространстве, дальше система сама интерполирует все это дело. Этот GPX-файл совместим с Android, iOS и Windows Phone, GPS-трекерами и т.д.
На самом деле этот инструмент был создан во времена бума Pokemon Go, спасибо им за это, очень сильно облегчило нам тестирование. Единственное, что если мы сгенерируем этим инструментом GPX-файл, система не будет определять скорость движения на iOS, поэтому, если вам нужно знать именно скорость, лучше использовать симулятор.
Давайте теперь поговорим про зеленое ведерко.
Козя:
Так как мы заметили, что эмулятор не такой богатый, как симулятор iOS, мы воспользовались тем, что мы можем поставить любое приложение без ограничений.
Первое приложение, которым я рекомендую воспользоваться — это Lockito, очень удобное, фактически заменяет вам симуляцию тех трасс, которые есть у Apple. Смысл в чем: вы запускаете приложение, указываете точки в пространстве, тип перемещения между этими точками (будь то по прямой или каким-то видом транспорта) и параметры выдачи координат, скорости и т.д. Запускаете симуляцию, после чего просто смотрите в вашем приложении, как вы вроде бы двигаетесь в пространстве.
Второе приложение — GPS Status & Toolbox. Чем удобен: его можно запустить в многооконном режиме, и посмотреть, как ваше приложение выглядит на маленьких девайсах, непосредственно на вашем большом девайсе. Ну и показать, что выдает система геоданных вашего девайса, что получает ваше приложение, и сравнить это. Если вы попали в какую-то аномальную зону, когда ваше местоположение не соответствует реальному местоположению (например, вас вдруг перебросило во Внуково), можете использовать GPS Test, чтобы понять, почему так произошло.
Учтите, что при использовании Lockito надо уметь пользоваться Location Mock, если ваше приложение пользуется библиотеками, которые решают за вас задачу использования каких-либо источников геоданных, о которых я говорил дальше. И если у вас в Android по умолчанию включены все источники геоданных, то вас будет часто перебрасывать при симуляции обратно в точку, где вы находитесь на данный момент. С чем это связано: любое приложение, которое эмулирует локацию, эмулирует только подсистему GPS, поэтому в настройках надо переключить такие источники данных, как GPS-данные, и все будет хорошо.
Давайте немножко резюмируем: мы поняли, что Maps to GPX Converter — это очень хорошо, можно загрузить одновременно GPX-файл на разные девайсы, и посмотреть, как различные операционные системы будут обрабатывать одинаковые маршруты. Ну и из коробки iOS, к сожалению, побогаче Android, зато Android зеленый, красивый и вообще лучше!
Теперь мы поняли, что наша система принимает данные. Теперь надо понять, что что-то хоть как-то работает, то есть начинать тестировать бизнес-логику.
Тестирование бизнес-логики
Для начала мы столкнулись с тем, что наша бизнес-логика была слишком большая, и мы не могли удержать все в голове. В чем была проблема: у нас было большое количество файлов, фич и классов, отвечающих за ту или иную систему обработки локаций. Чтобы снизить интервалы обработки геоданных или расстояние между получением координат, нужно было это все искать, менять, собирать приложение, и мы могли что-то пропустить, потому что в голове все не удержишь.
Для этого мы создали удобный файл конфигурации. Вот пример файла конфигурации на iOS, где вы просто можете поменять все необходимые данные, с вашим любимым Xcode собрать приложение и начать им пользоваться.
Хозя:
Следующая проблема, с которой мы столкнулись — это информационный шум, потому что без доказательств существования багов (допустим, скриншотов и подробных логов), разработчик зачастую может даже не понять, в какую сторону начинать копать. При тестировании геолокации это усугубляется тем, что в уравнении очень много переменных. Там не то что баг сложно воспроизвести, там иногда получить дважды подряд тот же самый набор координат с заданной точностью не представляется возможным. Поэтому без логов тестирование может создать больше информационного шума, чем реальной пользы, вы будете просто отвлекать ваших девелоперов.
Также, будем реалистами, зачастую разработчики добавляют логи для себя. Но даже если они добавляют логи для тестирования, зачастую они не до конца понимают, что нам нужно. Поэтому в нашем случае мы видели только координаты, которые отправляли на сервер. Поговорили с командой и решили, что же нам нужно от хороших логов, давайте с вами об этом тоже поговорим.
Для начала нужно понять, в каком режиме была зарегистрирована координата, Это может быть либо background, когда приложение в фоне или убито, либо foreground, когда вы видите UI приложения.
Дальше нам нужно понять, как она была получена: напрямую от GPS, или от каких-то других провайдеров, о которых мы поговорим немножко позже, или система могла сама запушить нам координаты, если мы используем то или иное API (допустим, geofencing, visits API или significant location change API на iOS).
Дальше нужно залогировать все, что можно о координате: точность, высота, скорость, вектор движения, время получения вплоть до миллисекунд. Это тоже очень важно, зачастую координаты измеряют свою точность скачкообразно с разницей в несколько миллисекунд. И любая другая информация, которая облегчит вам жизнь: например, как пользователь двигался (прыгал, бегал, ехал на велосипеде, плыл на лодке), включен или выключен Wi-Fi и т.д.
Ну и, наконец, нам нужно понять, по какому принципу мы будем все эти координаты отправлять.
Если у вас простая бизнес-логика, то это будет просто по таймеру, допустим, каждые 30 минут. Иначе это могут быть какие-то другие условия: либо описанная вами бизнес-логика, либо приложение было убито и затем оживлено. Оно может быть убито out of memory killer, вы могли сами его убить, или оно могло просто закрашиться. Оживить его может пуш-нотификация или какой-то API. Раз уж вы умерли и оживились, то будьте добры зарегистрировать и отправить координату на сервер.
Ок, мы собрали эти координаты и отправили на сервер, но почему-то не получили ожидаемого результата: или не пересеклись, или не зачекинились где-то. Идем ногами к нашим разработчикам, спрашиваем, что же не так. Клиентские разработчики говорят, не знаем, давайте пойдем к серверным разработчикам. Идем к ним, они помедитировали на PHP-код, поселектили в базе, сказали в чем проблема. В общем, мы сходили к ним пару раз и очень быстро их этим утомили, поэтому они сделали нам на основе собираемых логов очень удобную веб-страничку, где видим все наши передвижения, наложенные на гугл-карту:
На ней удобно рассматривать координаты с увеличенным уровнем зума на большом мониторе, вместо того, чтобы делать это на девайсе. Это помогло нам найти объяснения всяким странным ситуациям, происходящим в реальной жизни, когда мы думали «мы здесь», система определила, что мы находимся в другом месте. Иногда это делаем мы сами по какой-то ошибке, а иногда так находили баги на сервере, когда он неправомерно те или иные координаты отфильтровывал. В этом инструменте удобно, что отметки на карте закодированы цветами, и они показывают, почему та или иная локация невалидная (слишком часто регистрировалась/отправлялась, точность у нее низкая, либо что-то с ней не так). В общем, логи — это сила, рекомендую.
Козя:
Мы поняли, что с хорошими логами можно доказать, что это реально баг, а не фича, или же она воспроизводится, и взять девелопера
Именно debug menu сэкономило нам дополнительно семь килограммов нервных клеток. На Android меню простое. А если вдруг вам нужна более подробная информация, можете установить инструмент GNSSLogger от Google и получить еще больше дополнительной информации о том, как работает спутниковая навигационная система, вплоть до значений интерференции атмосферы в данной точке пространства. Я не знаю, зачем вам это может быть необходимо в большинстве случаев, нам это не надо, поэтому мы сделали простейшее меню. Вы можете видеть все о текущей локации, посмотреть карту перемещений, того, как вы перемещались. Очень удобный инструмент в субботу с утра, чтобы понять, что вы делали в пятницу вечером! Также есть система логирования, где записаны логи, ну и какие-то дополнительные инструменты: например, переключить систему геолокации с фейковой на настоящую, отправить логи на компьютер для дальнейшего их изучения, очень удобно, очень просто.
На iOS меню поприкольнее, но это же iOS.
Хозя:
У нас оно немножко посложнее, и мы его делали в один заход, в отличие от Android, где делали итерациями. Потому что мы сразу знали, что на iOS все плохо, и нам нужна вся эта информация! Самая первая переключалка, которой мы особенно гордимся — это локальные уведомления о работе location manager.
То есть вы можете свернуть приложение, убить, залочить девайс, но как только что-то изменится, вы получаете уведомление. Не то что не надо заходить в debug-меню и смотреть логи, а даже приложение не нужно запускать: девайс автоматически включает экран, когда вам приходит уведомление, это очень удобно. Так же чуть ниже у нас есть два набора координат: это последняя известная локация, и последняя отправленная, тоже для нашего удобства.
А также есть вьюшка с Apple-картами, на которых мы строим наши трассы движения, по той же причине, что и объяснял Коля: соединяем две точки и смотрим, были ли мы там. На ней есть интересный пин, который показывает временной промежуток. Чтобы его увидеть, необходимо воспользоваться Visits API, которая доступна с iOS 8, то есть уже достаточно долго. С точки зрения системы это работает достаточно хитро, потому что система за нас определяет, зашли мы в какую-то точку или вышли. Мы зашли куда-то, и примерно через пять минут нахождения там система понимает: «ага, мы, наверное, куда-то зашли», посылает нашему приложению уведомление, что в такое-то время вы зашли в точку с такими координатами. После того, как мы вышли, тоже примерно через пять минут она посылает точно такое же уведомление про выход. Соответственно, мы знаем, что провели там, допустим, 45 минут. Для функционала «Пересечений» просто великолепно: вы сидите и пьете кофе, мимо вас проходит огромное количество людей, вы с ними пересекаетесь. Просто великолепная API, жаль, что она не появилась с самой первой версии нашего сервиса. Мы его делали еще под iOS 7.
Все наши координаты, которые мы записываем, закодированы цветами, чтобы можно было быстро глазами пробежаться и понять, как она была зарегистрирована: белым цветом координаты в foreground, серым — background, фиолетовым — visit.
Мобильный тестировщик, поэтому и мобильный, потому что мы все свое носим с собой. В большинстве случаев нам этого debug-меню было достаточно, но основная проблема мобильных девайсов — это наличие аккумулятора.
Энергоэффективность
Козя:
И чем более энергоэффективно ваше приложение, тем дальше от розетки вы можете отойти. Напомню, это был 2014 год, было мало информации и о том, как тестировать энергопотребление, и о том, как правильно тестировать геолокационные сервисы.
Давайте поговорим об общих методах, которые мы нашли в первую очередь. Для начала мы воспользовались Power Meter. Это простейший девайс: с одной стороны он подключается к источнику энергии, с другой стороны подключается дата-кабель, к нему — ваш девайс, и показывает ток. А вот то, какой ток он показывает — это проблема.
Есть два случая. Первый: если ваш аккумулятор не заряжен, он показывает ток заряда, который потребляет ваш телефон, чтобы зарядить ваш аккумулятор. Это не совсем репрезентативные данные.
А если ваш телефон все же заряжен, то вы опять же не видите реального тока (за исключением Android, попозже расскажу). Потому что телефоны настроены таким образом, что если есть внешний источник энергии, то они выполняют еще синхронизацию, обновления приложений, а в последней версии Android еще и код компилируют за вас. Тоже нерепрезентативно. На андроиде вы можете отключить внешнее питание программно, тогда Power Meter будет, возможно, показывать верные данные. На iOS это невозможно.
Также существует специальный «метод Яндекса», о котором здесь, на Heisenbug, тоже есть доклад от парней из Яндекса. Но нам, к сожалению, этот метод не подошел, потому что мы не измеряем энергопотребление после каждого коммита, а двигаемся в разных режимах. Парни, простите, реально неудобно ходить на улицу с девайсом, у которого раскурочена задняя крышка, и подключена коробочка с Arduino, которая подключена к ноутбуку. Меня на улице, по меньшей мере, не поймут!
Давайте поговорим о методах измерений непосредственно на девайсах. Первым делом поговорим об Android, потому что он на букву А.
Самое первое, что можно сделать на Android — это зайти в настройки энергопотребления, и посмотреть, что вообще творится. Если вам жутко не повезет, то вы увидите ваше приложение в списке на одном из первых мест. Хотя, понятное дело, если вы постоянно пользуетесь вашим приложением, то оно появится в топе в любом случае, просто потому что вы им так много пользуетесь.
Зайдя в расширенную информацию энергопотребления на последних версиях Android, вы можете видеть очень много полезной информации: использование CPU в foreground, в background, использование датчиков (например, GPS), и т.д.
Почему здесь дополнительно есть Google Play Services? Одно и то же приложение на разных версиях Android будет иметь различное энергопотребление: до Android 8.0 ваше приложение при использовании Google Play Services вызывало энергопотребление этих «сервисов», а не ваше энергопотребление. К восьмой версии Google понял, что пользователи слишком много жаловались на «выжирающие батарейку Google Play Services» и сказал: «Хорошо, теперь любое энергопотребление, которые было вызвано вашим приложением, идет обратно к вам». И вы видите свое реальное энергопотребление, поэтому поставьте восьмерку и ужаснитесь или обрадуйтесь.
Следующий метод, который мы начали использовать — это Test Fairy, библиотека-sandbox, встраиваемая в ваше приложение и записывающая большое количество данных. Мы используем ее в случае с бета-пользователями, они получают за это всяческие плюшки вроде бесплатных кредитов, а мы получаем от них большое количество данных.
Одни из этих данных — это энергопотребление, но и здесь не все гладко. У пользователя сессия в основном 1-2 минуты, потом она закрывается, начинается новая, и изменение аккумулятора за этот период не такое уж интересное, оно вообще может равняться нулю (шкала там не в мАч, а в процентах, и на современных девайсах с аккумуляторами 3000+ мАч один процент довольно велик). Или же у пользователя может быть длинная сессия, как этот пользователь с 22-минутной сессией, но его телефон был подключен к источнику энергии, поэтому мы ничего не видели. Остальных пользователей, у которых реально происходит разряд, настолько мало, что данные просто не поддаются толковому анализу.
Следующий инструмент, который я начал использовать сразу же, как только он вышел — это Battery Historian. Спасибо компании Google, уникальный инструмент, является фактически «дактилоскопом» для определения, кто все-таки и когда жрал батарейку. Даже если вы не исследуете свое приложение, вы можете увидеть, какие другие приложение и почему ели батарейку.
Здесь видите, что я выбрал момент времени, кликнув на график, вижу, что наше приложение было активным 3 минуты. Вижу, какие сенсоры использовало, какие сервисы, и особенно это помогает при исследованиях энергопотребления: позволяет понять, геолокация ли жрет приложение. Бывает, что developer случайно создал infinite loop и забыл сделать из него выход. Всякое бывает.
Для того, чтобы дополнительно прикрыться с тыла, мы используем мониторинг. У нас очень сильная команда мониторинга, и помимо всех метрик, они по нашей просьбе еще мониторят энергопотребление наших пользователей, и после релиза мы можем видеть тренд и оперативно реагировать на него.
Система работает очень просто, мы два раза посылаем ивенты о заряде аккумулятора: один раз, когда приложение стартует, а второй раз, когда приложение сворачивается или убивается. Мы на основе этого строим тренды, очень удобно, очень полезно, и мы хорошо прикрыты. А на iOS все боль.
Хозя:
Как обычно, на iOS все классно для пользователей (не так легко выжрать батарейку, как на ранних версиях Android), но для инженеров большая печаль.
Мы начали с самого первого инструмента, то же самое: «Настройки» — «Аккумулятор». Инструмент в целом очень плохой, у него есть всего один плюс: показывает, сколько ваше приложение работает в бэкграунде. Для нас это важно, потому что мы собираем и отправляем геолокацию в том числе в фоновом режиме.
А дальше начинаются боль и страдания. Инструмент очень инерционен, обновляется примерно раз в час. Поэтому, если ваше приложение 5 минут работает нормально, а 55 жрет батарейку, как не в себя, вы этого не видите. А если вы захотели заресетить два девайса, поставить на них два разных билда и сравнить их по энергопотреблению, то мало того, что первый результат увидите через час, так если не запустите три или более приложения, вы вообще ничего не увидите, и еще раз отложите все на час.
Следующий инструмент — это Energy impact шкала в Xcode. Подключаетесь дебаггером к вашему приложению, нажимаете третью ячейку сверху и видите шкалу, которая изменяется в реальном времени: от зеленой зоны, где не потребляете энергии, до красной, где жрете, как не в себя.
Чуть ниже показано, почему потребляется: допустим, CPU загружен на 100%, или вы не даете системе заснуть, или все время ее будите, или забыли погасить GPS после того, как он не нужен. Но без разработчика с этим разобраться достаточно сложно: например, потому что при запуске вы будете жрать CPU потому что надо запустить приложение и прогрузить данные, у вас будет включен GPS, чтобы отправить локацию на сервер и получить людей рядом с вами, и еще будете скидывать кэш на диск. Нормально это или ненормально, черт его знает. Поэтому мы разработали сет кейсов и прогоняем с разработчиками после каждого большого рефакторинга.
Следующий инструмент — это настройки энергопотребления в вашем айфоне: заходите в «Settings — Developer — Instruments», включаете запись энергопотребления и работы с сетью. Работа с сетью опять нам пригодилась, потому что мы отсылаем эти координаты на сервер.
Но инструмент, опять же, не очень, потому что он пишет данные обо всей системе, между приложениями что-то сравнить тоже сложно — их вагон в списке. Данные об энергопотреблении показываются какими-то непонятными на первый взгляд дробями, а не миллиампер-часами, как на Android. Дроби, как ни странно, показывают сколько девайс будет жить с текущим энергопотреблением. Например, 1/17 значит, что в данный срез времени при текущем энергопотреблении девайс разрядится в ноль за 17 часов.
Для того, чтобы писать данные конкретно по вашему приложению, нужно подключать instruments именно к вашему приложению. Если вы будете ходить по улице с ноутбуком, шнурком и девайсом, вас могут не понять.
Вот такая печаль iOS, я надеюсь, в докладе ребят из Яндекса что-то классное будет, что с этим поможет. А вот у ребят на Android все классно — Battery Historian, графики, ребята прикрыты со всех сторон.
Наши оптимизации и решения по энергопотреблению
Хозя:
Мы поговорили о том, как измеряли энергопотребление, теперь давайте поговорим о том, как принимали те или иные решения для оптимизации. К счастью, наши разработчики классные и читают документацию, но если где-то что-то пропустили, команда тестирования идет на помощь. В большинстве случаев мы проверяли ту или иную теорию, и она подтверждалась либо опровергалась. Открываем документацию по Location Manager в iOS и видим, что первым делом Apple рекомендует вам снизить настройку точности при определении местоположения, и мы ее снизили до 100 метров.
В любом случае система будет стараться вам дать координаты как можно точнее. Как минимум потому что у вас на девайсе, скорее всего, есть другое приложение, которое использует геолокацию. То есть вы можете ее получить «за чужой счет»: если другое приложение получило локацию, вы можете ее использовать. Например, пять минут назад другое приложение получило геолокацию, в принципе, иногда достаточно. «Расслабление» настроек позволяет Apple сэкономить на энергопотреблении.
Но, как обычно, сложно быть сразу умным и красивым, причем не только на iOS, но и на Android. Например, вы долго были на парковке либо ехали на поезде с большой скоростью, у вас была низкая точность. Вы запускаете приложение, и у вас есть два способа получения координат: либо быстро, но не точные координаты (вплоть до 1000 с чем-то метров), либо долго и точно. Но, как Коля говорил раньше, «долго и точно» вообще не гарантирует ее получение, если вы в подвале, то можете ждать 15 минут и не получить (вы, например, в подвале). Поэтому мы выбрали путь «быстро, но не точно», и разработали механизм изучения координат.
Это отвечает на вопрос, зачем нам нужна была селфи-палка во время тестирования. Берем девайс, ноутбук, шнурок, подключаемся к дебаггеру, спускаемся на парковку, лочим девайс, ждем две минуты, чтобы система полностью заснула. Дальше заходим в лифт, поднимаемся на четвертый этаж, быстро бежим к окну, по пути разлочивая девайс, выставляем девайс на селфи-палке за окошечко и видим, как система одним или несколькими шагами уточняет местоположение. Это, конечно, весело и интересно, к счастью, это покрыли unit-тестами, и ни один телефон не пострадал.
В общем и целом, механизм уточнения работает просто: в течении 20 секунд (после запуска приложения либо после того, как мы вывели его из фона) мы слушаем координаты от системы с возрастающей точностью. 20 секунд — это таймаут, выбранный эмпирически после экспериментов на подвалах и парковках :) Через 20 секунд мы отправляем более точные координаты, если они есть, а если нет, то мы потихоньку умираем и все.
Дальше мы решили использовать Significant location change API. Вместо того, чтобы будить приложение и включать GPS (что очень неэкономично), вы подписываетесь на API, и система сама пушит вам уведомления о значительном изменении координат, вам их надо только сохранять в базу и отправлять. Очень классно.
Что именно означает «значительно», «significant»? Это неизвестная величина, она зависит от скорости движения, режима движения, энергопотребления, режима сохранения энергии, очень много неизвестных. В общем и целом, при ходьбе пешком это 750 метров, при езде на автомобиле с небольшой скоростью это от 750 метров до нескольких километров. По энергопотреблению это вам практически ничего не стоит, надо только записать координаты либо сразу их отправить. Но, как обычно, у Apple все опять плохо.
Мы не можем сделать сервис, который работает только с координатами и перекачивает данные в приложение, как на Android. А значит, если нас прибило и потом оживило, то нам нужно оживлять все приложение. Чтобы жрать батарейку чуть-чуть, а не очень сильно, нам приходится инициализировать только части нашего приложения. То есть мы инициализируем систему работы с сервером и систему по работе с локацией: мы не грузим encounters (наш первый и основной экран), не инициализируем какие-то скрины, и так далее. Иначе это была бы беда.
Также мы используем Visits API. О нем я уже рассказывал раньше, но наша первая версия работала с API iOS 7, поэтому изначально его не было.
Также во время сбора и отправки координат и выполнения всяких задач Apple рекомендует дать послабление времени, плюс-минус несколько секунд, чтобы система сформировала пачку задач, проснулась, выполнила всю пачку задач и обратно заснула. Иначе она будет просыпаться под каждую задачку и жрать вам батарейку.
Ну и последнее: мы придушили немного таймаут при работе с сетью. По умолчанию на iOS это 120 секунд, как и время работы NSurlsession в фоне, которую мы используем при отправке координат на сервер. Это очень много, мы это придушили, если мне не изменяет память, до 30 секунд. То есть если у нас плохая сеть, мы чуть-чуть подолбили сервер и не получили ответа, то умерли, и перезапланировали отправку, допустим, на 5 минут в будущее. Если это делается 120 секунд, мы, опять же, начинаем выедать батарейку. Особенно, если у вас нет Wi-Fi, а есть 3G: работа с сотовой сетью менее энергоэффективна
Давайте теперь поговорим про Android.
Козя:
На Android мы сразу же после появления Fused Location Provider начали им пользоваться. Его характеризует низкое энергопотребление, потому что библиотека сама за вас решает, какой источник геоданных выбирать. Не всегда GPS является самым оптимальным и быстрым способом нахождения вашей геопозиции.
Второе достоинство — это возможность получения геолокации за чужой счет. Как говорил Саша, они не могут создать сервис на iOS, а мы на Android сервис создать можем. Что мы и сделали, и просто получаем локацию за чужой счет, подписавшись: если какому-то другому приложению нужна локация, например, Яндекс.Навигатору, мы получим эту локацию себе, просто сохраним в базу и потом отправим, а все энергопотребление уйдет на навигатор.
Также можно задать нужную точность, чтобы ваш сервис не получал большое количество координат. Потому что, как мы вчера проверили в московском метро, точность бывает и до пяти километров. Можно задать нужную точность получения, например, «нам нужны координаты с точностью 100 метров и точнее», и остальные будут отфильтровываться системой, очень удобно. Также есть разные стратегии: получение по таймеру, получение в случае запуска какого-то сервиса, пользователь вошел в какое-то место. Стратегий много, поэтому читайте документацию и найдете то, что вам лучше всего подойдет.
Тут я бы закончил говорить про наши оптимизации, если бы не там проблема, что Fused Location Provider закрывает лишь 90% наших потребностей. А ещё 9% закрывает Legacy Location Provider — это старый провайдер, который был в Android с давних времен. Им можно пользоваться, но он не такой энергоэффективный и нужен для старых девайсов, которые не поддерживают новые типы Google Play Services, или же для девайсов без Google Play Services, например, от неизвестной китайской компании Xiaomi.
Остальной процент данных закрывает самописная система, которая называется Aggressive Location Provider. Она основывается на Legacy Location Provider, и нужна по крайней мере для двух случаев:
Во-первых, бывает так, что Fused Location Provider вообще не вернул удовлетворяющие нас координаты (например, ваше приложение является единственным приложением в системе, которое обрабатывает геоданные, а вы решили подписаться за чужой счет и ничего не получили). А наши продакт-менеджеры хотели от нас большого количества координат, и мы так перестраховались.
Второй случай. Google Play Services — это приложение, которое пишется людьми, так что оно тоже может «умереть», может неправильно перезапуститься после обновления, и может произойти много других вещей, поэтому дополнительная подстраховка — это всегда важно.
При этом у Aggressive Location Provider очень трепетное отношение к заряду аккумулятора пользователя. Например, в случае падения заряда меньше 20%, переключения телефона в режим полета или ручного включения режима энергосбережения, мы перестаем использовать Aggressive Location Provider и вообще трогать телефон в этом плане. Чтобы уважать пользователя и его настройки.
Кроме того, есть Activity Recognition API в составе Google Play Services — удобная система паттернов активности пользователя. Существует 4 основных паттерна: хождение, бег, велосипед и нахождение в транспорте (будь то общественный или свой).
Кроме того, есть дополнительные паттерны, например, очень удобный still. Например, вы взяли свой девайс, зашли в какой-нибудь бар, положили девайс на стол, чтобы общаться с другими людьми, и ваш телефон лежит неподвижно. Паттерн still сработал, мы получили эту информацию и запоминаем местоположение недалеко от того момента, когда мы получили still, или же просто пытаемся уточнить местоположение сейчас. После чего мы забываем о вопросе местоположения девайса до того момента, как пользователь не взял телефон, чтобы выйти из бара, потому что он уже наобщался. И мы поймем, что с такого-то по такое-то время пользователь был неподвижен в этой точке.
Тут все хорошо, за исключением некоторых случаев: например, вы едете на поезде Санкт-Петербург-Москва, положили телефон на полку, у поезда идеальная подвеска, железная дорога прямая, ваш телефон оказывается в режиме still. Вы приезжаете в Москву, хотите посмотреть, пересеклись ли вы с той девушкой в Вышнем Волочке или нет, но, к сожалению, вы не пересечетесь, потому что мы получили still, и, возможно, все время думали, что вы находились на Московском вокзале Санкт-Петербурга. Поэтому нужно все же перестраховываться и слушать систему: если локация все-таки меняется, то инвалидировать паттерн, потому что паттерн — это лишь вероятность.
Итак, вы обкатали все, что у вас есть в ваших лабораторных условиях, поняли, что это как-то работает, но все равно это сферический конь в вакууме, потому что в реальных условиях могут быть те или иные ситуации, вам нужно начинать их понимать. Для этого вам придется выходить «в поле».
Выход «в поле»
Козя:
И для того, чтобы выходить в поле, вам нужно понять, что с собой брать. Нужно брать реальные девайсы, с различными версиями ОС, включенным/выключенным Wi-Fi, с различными настройками энергосбережения, с сим-картами и без них. Хочу заметить, что две различные сим-карты могут иметь различное энергопотребление: например, одни поддерживают 4G, а другие нет. Бывает так, что даже две сим-карты, которые поддерживают одинаковые частоты, имеют различное энергопотребление, потому что у них разные прошивки. Мы с Сашей столкнулись с этим, пользуясь сим-картами Vodafone из разных партий.
Дальше вам нужно понять вашего пользователя. Потому что, чтобы найти баги пользователя, нужно быть, как пользователь, нужно двигаться, как пользователь, делать вещи, которые делает пользователь. Ну и быть пользователем вашего приложения, в конце-то концов, dogfooding никто не отменял. И вот чем мы занимались.
Хозя:
Первым делом мы решили выйти из офиса и немного прогуляться по окрестностям. Чем это так удобно? Да тем, что очень сильно гуляет точность определения местоположения из-за различной плотности застройки, различной плотности сетей Wi-Fi и сотовых сетей. Лондон очень неравномерный.
Также «рваный» темп хождения позволяет проверить интервалы отправки. Вы не ходите с одной скоростью: кто-то перед вами затупил, вы кого-то обогнали, постояли на пешеходном переходе, спустились в подземный переход и так далее. Конкретно в нашем случае это даже позволило найти нам баг. Если во время формирования пачки координат перед отсылкой получали координаты, они добавлялись как в пачку на отправку, так и в кэш. Соответственно, в редких случаях мы дублировали эти координаты. Воспроизвели, если по-честному, случайно, но кейс интересный.
Также очень удобно тестировать «визиты» на iOS. Напомню, что расстояние между двумя точками signification change — это 750 метров, и «визиты» присылаются с задержкой спустя плюс-минус 5 минут. Почему это удобно: расстояние между пабами в центре Лондона значительно меньше этих 750 метров.
Поэтому вы заходите в паб, пьете пинточку, выходите, за 5 минут доходите до следующего паба, и тут может что-то не то произойти. Конкретно в случае iOS мы зажевывали либо выход из предыдущего заведения, либо вход в следующее, если они по времени оказывались очень близко. Помогло нам переписывание всего этого дела на Swift, потому что static analyzer там работает значительно лучше и помог нам определить что мы использовали неправильную константу и выражение всегда ложно.
В общем и целом, тестировать легко и приятно: пьете пинточку (обычно я пил пинточку с Козей), пересекаетесь, получаете push, открываете его, смотрите. Если место правильное, и/или мы уже натестировались — надо идти домой.
Также хождение по всяческим заведениям позволило найти потенциальный баг, который мог развалить всю нашу систему обучения чекинов. В Лондоне, помимо пабов, очень много всяческих заведений на квадратный метр. Скажем так, на площади 100-200 квадратных метров может быть 4-5 кафешек. А точность у нас обычно 10-30 метров. Поэтому определить, что вы в конкретной кафешке, очень сложно. И мы поступаем достаточно нетривиально: заходим в кафешку, получаем событие входа, забираем подключенную точку Wi-Fi и ее MAC-адрес (если, конечно, она есть), и отправляем на сервер. То есть если пользователи постоянно заходят в эту точку, у них тот же самый Wi-Fi, то с большой долей вероятности вы находитесь-таки в этом месте.
Но, как оказалось, в Лондоне еще есть открытые сети Wi-Fi, и за три минуты я могу дойти до следующего заведения и уже находиться в нем, и опять захватить точку доступа и отправить на сервер. Мало того, что сервер обалдел, от того что у него две различные Wi-Fi-сети на событие входа и выхода, так еще и физически между ними расстояние может быть 300-400 метров. В зависимости от того, насколько быстро вы ходите, это надо учитывать, поэтому волевым решением мы отключили запись имени точки доступа на событие выхода из места.
Дальше мы решили покататься на общественном транспорте. Первым делом — на автобусах, потому что центр Лондона очень забит, а автобусы ездят с низкой средней скоростью. Также это позволило проверить и оттюнить определение характера движения: едете вы, идете и т.д. Такое определение — это вероятность, то есть при езде на автобусе, условно, с вероятностью 90% вы будете определяться едущим на автобусе, а с вероятностью 10%, допустим, на велосипеде. В некоторых случаях вам соответствующие веса надо будет подтюнить.
Также при езде на автобусе мы поймали забавный серверный баг. При остановке на пешеходном переходе либо на светофоре мы иногда получали location. Так как сервер не знал, через какое мы получим следующую локацию и что мы до этого тормозили, то пытался чекинить нас в ближайшем заведении к автобусной остановке. Решили мы это проблему просто: мы добавили определение скорости (в метрах в секунду), и если скорость не нулевая, то чекинить нас в этом заведении не надо.
Дальше мы решили спуститься в лондонское метро. Оно очень старое, там нет сотовой сети, не ловит GPS, поэтому наименее читерский способ определения местоположения — по Wi-Fi: заходите в вагон, доезжаете до следующей станции, у вас автоматически подключается Wi-Fi, определилось местоположение, тоже очень классно и удобно.
Дальше мы решили покататься на автомобиле и на такси. Чем это удобно: операционная система пытается тюнить энергопотребление, если вы двигаетесь с большой скоростью, и у вас не включен навигатор. Поэтому при езде со скоростью 20-30 км/ч это 750 метров в фоновом режиме, а при езде 110 км/ч — уже 2-4 км, а если вы едете на скоростном поезде до аэропорта (у нас в Лондоне ездят примерно 250 км/ч), и у вас не так много сотовых вышек, это уже 4-11 км в зависимости от плотности вышек, потому что быстродвижущиеся объекты GPS зафиксировать достаточно сложно, и в поезде много металла, который не способствует точности определения местоположения.
Также в зависимости от скорости движения, если вы используете Geofencing API, необходимо правильно выставлять радиус. Geofencing работает достаточно просто: вы заходите в точку, ставите вокруг себя радиус, по выходу из него делаете какое-то действие (допустим, отправляете пачку координат). Либо, наоборот, вы заходите в определенное место. Допустим, заходите в McDonalds, вас идентифицируют и шлют push «сегодня для вас бургер в два раза дешевле». Если вы двигаетесь быстро, то необходимо поставить радиус побольше. Иначе вы будете высаживать аккумулятор, будете часто выходить из этого радиуса, или, наоборот не будете из него выходить, если точность координат его превышает.
Козя:
Помимо этого, в Android 7+ может произойти другой прикол. У вас есть телефон, вы садитесь в машину, кладете его на пассажирское сиденье, едете из точки А в точку Б. Доехали, хотите посмотреть, сколько локаций получил ваш телефон, смотрите, а их нет вообще. С чем это связано? Google решил сделать пользователям хорошо, а разработчикам плохо, и ввел так называемый doze, режим сна. Мало того, что когда телефон не используется, он «спит», так еще и с версии Android 7.1 Google добавил агрессивный doze. Чем он плох: ваш телефон начинает быстрее анализировать ситуацию, понимать, что он не востребован, как раз в случае, когда вы его кинули на пассажирское кресло и едете в точку Б, и в итоге не получает координаты. Почитав документацию, обнаружили, что можно получать координаты хотя бы четыре раза в час — с паршивой овцы хоть шерсти клок.
Мы поняли, что наш конь уже не сферический, а реальный. Давайте теперь поговорим о самом страшном.
Обратная сторона полевых выходов
Козя:
Первая страшная вещь — то, что девайсы могут ломаться и падать, поэтому запасайтесь хорошими чехлами перед любым полевым выходом.
А второе — это регрессия.
Хозя:
После того, как мы проверили багфиксы, основную функциональность, первым делом мы задаемся вопросом: не просели ли мы по количеству собранных и отосланных координат? Кэп намекает, что надо взять два девайса, поставить на них различные сборки и прогуляться с ними, сравнить координаты. Но как бы не так. Коля раньше говорил про сим-карты с различным энергопотреблением, а мы столкнулись с еще одним интересным способом доказать, что девайсы очень сложно поместить в одинаковые условия.
У меня был один тестовый девайс в правом кармане, а другой — в рюкзаке, потому что в задний карман опасно класть, могут вытащить. Как оказалось, при ходьбе девайс, который был в кармане, больше двигается, чаще просыпается и собирает больше координат. Придя на работу, я увидел, что девайс, который находился в рюкзаке, собрал их раза в полтора меньше, и различные билды приложения не имели к этому отношения. Поэтому старайтесь помещать девайсы в максимально похожие условия.
Также мы рекомендуем вам долговременную проверку сервиса в фоне, потому что в современных девайсах омерзительно большое количество оперативной памяти. Например, есть модификации OnePlus 5 на 6 и 8 гигабайт RAM, в таком случае ваше приложение в фоне будет жить очень долго, а раз оно живет, то пусть и работает правильно. Мы обычно оставляем приложение, подключенное к дебаггеру и в режиме симуляции движения на ночь или на выходные.
Но круче всех нам с тестированием помог Коля, когда во время релиза этой функциональности ему пришлось перегонять автомобиль из Москвы в Лондон. Мы ему выдали несколько коробок тестовых девайсов, он за два дня и 3000 километров собрал нам огромное количество координат, пересекся с юзерами, у которых была выключена фича (и сам с собой в том числе), собрал нам гигабайты логов, помог найти несколько багов, которые поправили перед запуском.
Давайте теперь поговорим о багах, все-таки у нас конференция по тестированию.
Козя:
После релиза фичи нам начали приходить координаты из прошлого и из будущего. Чем вызвана проблема: наши пользователи двигаются и могут пересекать часовые пояса, уходить в прошлое и будущее относительно того timestamp, в котором были получены первоначальные координаты.
Помимо багов девайсов и прошивок в определении timestamp при пересечении часовых поясов, подобные ошибки оказываются вызваны и другими багами, но решить это можно просто. У девайса всегда есть время, которое больше нуля — это uptime, время с момента запуска. Мы его складываем при получении координат, и уже потом, когда эту пачку координат нужно отправить на сервер, отправляем с uptime-временем. В принципе, это закрывает большинство проблем.
Вторая проблема — это люди, которые начинают телепортироваться. Помимо вещей, о которых я ранее говорил (пользователь резко меняет координаты, чтобы докучать другим пользователям, или же угнали аккаунт), вполне реальный пользователь тоже начинает телепортироваться в пространстве. С чем это связано: в первую очередь, с тем, что при уточнении координат, точка может гулять. Уточнение координат и смещение центра может происходить с очень большой скоростью. И мы просто ограничили максимально возможную скорость перемещения наших пользователей скоростью пассажирского лайнера, больше пока что нереально. Это решило 99.9% проблем, за некоторыми интересными исключениями.
Хозя:
Напомню: если у вас не ловит либо выключен GPS, локация берется от включенного Wi-Fi либо базовой станции. Мы столкнулись в природе как минимум с двумя кейсами ошибок. Первый — когда отмечали 10 лет компании Badoo в красивом загородном доме с очень толстыми стенами и потолком, соответственно, у нас не ловился GPS. Наши доблестные админы притарабанили точки доступа из лондонского офиса, и при запуске приложений карт и нашего приложения получалось, что мы находимся именно в лондонском офисе. К счастью, современные точки доступа умеют обновлять свои местоположения довольно быстро, от нескольких минут до нескольких дней. У нас все это дело пофиксилось через пару-тройку часов.
А те, кто живут в Москве, знают более популярную историю: если вы подходите к Кремлю, то вас может «телепортировать» во Внуково, и с нами это тоже случалось. Погуглив, мы обнаружили, что подменяют координаты GPS/ГЛОНАСС и выставляют координаты Cell ID во Внуково. Ребятам из Яндекс.Такси приходилось даже делать хак, чтобы более-менее нормально подвозить или забирать людей оттуда.
Также некоторых юзеров телепортировало в Китай и Бразилию. Как оказалось, в Бразилию телепортировало в основном с девайсов Blackberry: оказывается, когда у них что-то случалось с подсистемой работы GPS, их телепортировало на место сборки устройства в Бразилию. А в Китай перебрасывались китайфоны, у которых что-то пошло не так.
Также перебрасывало между двумя точками некоторые девайсы на iOS. Если не изменяет память, до версии iOS 9.2 у них был очень противный баг: при получении локации в фоне система с разницей в 10-15 миллисекунд допушивала очень старую локацию, допустим, полученную 6-8 часов назад. Вы идете вперед, потом прыгаете назад, потом идете вперед. Ради этого нам пришлось писать фильтрацию устаревших координат: как на клиенте, так и делать костыли на сервере, все-таки на клиенте не всегда возможно это сделать. Сервер просто сглаживает это все дело.
Последний баг, который лично мне попил немало крови: если вы симулируете геолокацию на реальном девайсе, и в этот момент «поплохело» Xcode, или вы выдернули шнурок во время сессии дебага, девайс замрет в последней известной ему геолокации. Курьезность ситуации в моем случае состояла в том, что я перед выходом домой симулировал точные координаты нашего офиса, взял этот девайс домой, а потом вернулся и с удивлением увидел, что он не получил координаты ни разу, в итоге это стоило нескольких человеко-часов — моих и разработчика.
Мы все рассказали, что хотели, давайте просуммируем.
Заключение
Козя:
Самое первое, что мы поняли: без хорошего инструментария, будь то IDE, логи или дополнительные приложения, тестирование геолокационных сервисов будет создавать больше информационного шума, чем приносить реальной пользы.
Необходимость полевых выходов при тестировании геосервисов очевидна, но проблема в том, что даже выйдя в поле, вы не найдете все баги. Мы описали лишь некоторые подводные камни, у вас их может быть намного больше, или вообще не быть, в зависимости от того, как вы этим занимаетесь.
Все баги, найденные вами, желательно классифицировать и каким-то образом отмечать. Это могут быть баги вашей функциональности, баги API, непосредственно самого девайса или же геолокации, как в случае с перебросом во Внуково. Эти баги нужно иметь в виду, чтобы в случае нахождения, сразу быстренько говорить: это баг класса «геолокация», и мы его фиксить не будем, потому что не имеет смысла.
Тестировщики являются связующим звеном между пользователем и бизнесом. Понятное дело, что бизнес от нас хочет, чтобы было много координат, а пользователи не очень любят, когда их аккумулятор резко садится. Именно из-за этого нужно задумываться об измерениях энергопотребления как можно раньше. Но при этом важно и не переоптимизировать на очень ранних этапах разработки, потому что потом будет сложнее как тестировать, так и разрабатывать.
И самый главный вывод, который мы можем сделать сегодня на этой конференции: плотность пабов в СНГ намного меньше плотности пабов в Лондоне, и, если вам вдруг понадобилось с точностью протестировать ваши геолокационные сервисы, прогуляться по достопримечательностям, приходите к нам, мы с удовольствием вам поможем. Спасибо!
Ссылки по теме:
- Измеряем потребление батарейки на мобильных устройствах. Эксперимент в Яндексе
- Работа с сенсорами
- Хардкорная локация
- Локация от Google
- Android location and sensors API
- Location strategies
Минутка рекламы. Если вам понравился этот доклад с конференции Heisenbug — обратите внимание, что уже подступает новый Heisenbug (17-18 мая, Санкт-Петербург), в его программе тоже много интересного, и её уже можно внимательно изучить. Надеемся увидеть там многих из вас!