- PVSM.RU - https://www.pvsm.ru -
Однажды, ваше мобильное приложение становится достаточно большим и им ежедневно пользуются десять тысяч — сто тысяч — миллион, не важно, в общем очень много живых и разных людей. Что это значит для вас, как для разработчика?
Да, теперь стало гораздо страшнее нажимать кнопку «Submit», ведь если вы чего-то недоглядели — в отличии от веб-приложений не получится посидеть ночь, обложившись банками ред-булла и пиццами и все исправить — ревью на мобильных платформах занимает время, а если говорить про iOS — аж целую неделю. Неделя — более чем достаточный срок для того, чтобы лояльный ранее пользователь перестал открывать ваше приложение.
А еще, что не менее важно, это значит, что наступило время, когда «мне нравится, как выглядит этот экран» — уже недостаточное оправдание для того, чтобы этот экран действительно присутствовал в приложении.
В этой статье я постараюсь рассказать о том, что мы делаем, чтобы огромное продакшн-приложение продолжало оставаться таковым.
В качестве примечания: материал данной статьи мало подходит для приложений, работа которых не требует соединения с интернетом. Но в наше мобильное время — таких остается все меньше.
История первая: Мы интегрировали в наше приложение работу с одним большим и очень красивым third-party. У них своя команда, свой бэкенд, даже свой офис в какой-нибудь солнечной стране, куда можно позвонить и записаться на прием. Но в один прекрасный момент весь этот сервис ложится дня так на три после солидного рефакторинга, который по забавной случайности, нарушил обратную совместимость. Да «напишите это сами», «не связывайтесь больше с ними», «попросите их поскорее все исправить» — это, конечно, интересные мысли для размышления, но делать нужно что-то и причем быстро, для того чтобы пользователи, нажимая на какую-нибудь из привычных кнопок не видели постоянное «Простите, у нас обед», или того хуже — какую-нибудь не очень соответствующую правде информацию.
История вторая: Вы деплоите большую и важную фичу и, разумеется, вы ее как следует протестировали, но при этом в ней все-таки что-то оказалось не так! Кого и как поругать — будем решать потом.
История третья: Для того, чтобы больше знать о пользователях вашего приложения, вы отправляете на ваш выделенный лог-сервер много полезной информации. Но кто-ж знал, что их, внезапно, стало несколько миллионов — и ваша лог-сервер радостно падает раз в 10-15 минут, а новый прибудет недели через 2-3.
Это страшные истории, а еще есть много других, не таких страшных.
И для них всех есть одно удобное и полезное средство — сегментация.
Если вкратце — флоу работы нашего приложения можно описать простыми шагами:
Итак, теперь остановимся подробно на первом и третьем шаге и на том, какие проблемы они решали в те или иные моменты жизни:
Что такое общий конфиг? Это набор настроек приложения, одинаковый для всех пользователей.
Что в нем содержится:
Entry-point вашего приложения. И теперь, если случится то, что вам потребуется переехать на другой домен или, например, перевести пользователей на резервный сервер — это можно будет сделать через конфиг. В отличии, опять же, от веб-приложений, для мобильных (и для десктопных) систем — одновременно живы могут быть довольно большое количество версий, а значит вынужденное изменение продакшн-сервера можно провести (а у нас это было, значит может случиться и с вами), не сломав клиенты, которые уже в работе.
Таким образом в приложении будет храниться ровно один статический URL — на файл конфига, а за ним уж как-нибудь можно уследить.
В целом, люди не очень любят обновляться. И даже с появлением на мобильных платформах автообновлений — ситуация улучшилась, но не исправилась во всей ее полноте. Например у нас — при двухнедельных циклах релизов — используются, как правило 10-15 версий одновременно. Но иногда происходят, так называемые breaking changes — фундаментальные изменения, которые делают невозможной/некомфортной работу на старых версиях клиента. В таком случае этот параметр сигнализирует нам о том, что «было бы неплохо обновиться» в мягком сценарии и «без обновления продолжение работы невозможно» — в жестком, что мы и показываем в UI для пользователей.
Для этого мы используем отдельный конфиг-файл, который позволяет нам:
Первое помогает нам, имея достаточно компактные лог сообщения — при необходимости добавлять в них ту информацию, которой нам недостает.
Второе помогает нам балансировать нагрузку на лог-сервер. Так как пользователей у вас уже действительно много, то даже, если 1 процент из них будет отправлять эти сообщения на сервер — это уже позволяет нам получить достаточно репрезентативную картину.
Третье же имеет немного другую пользу — иногда в нашей системе крэш-аналитики появляются крэши, обстоятельства которых сложно восстановить по stackTrace, тогда уменьшая лог-левел до предела мы просто прикладываем последние сколько-то строк системного лога к крэш-репорту и уже на следующий день мы можем восстановить действия пользователей и локализовать проблему (если кому интересно, у нас это достигается в связке логгера cocoalumberjack и HockeyApp аналитики).
Да, я понимаю, что это фуфуфу, но тем не менее, в случаи каких-либо неоднозначных ситуаций с этими библиотеками — нам несколько раз приходилось пересоздавать наши аккаунты в third-party — и это, опять же, не ломало работу старых клиентов. К тому же, эти ключи вполне можно «посолить» и сделать их достаточно безопасными. (Но мы же все равно помним, что если вредитель задастся целью — он сможет вытащить и из бинарного приложения статически заданные эти ключи — поэтому такой способ их хранения не слишком хуже — тем более что вытащить алгоритм шифрования сложнее, чем один ключ).
К тому же, иногда в случае особенно неприятных breaking changes в third-party можно себе позволить устроить проксирование работы с ними через ваш сервер, сохранив для старых клиентов старый формат.
Некоторые решения необходимо принимать для пользователя, который еще не зарегистрирован в системе (например, внешний вид окна регистрации, путь, по которому мы проходим регистрацию и многое-многое другое). В таком случае в качестве такого параметра мы вполне можем хранить процент пользователей, для которых требуется включить/выключить некоторую функциональность. Для определения попадания в тестовую группу неплохо подходит какой-нибудь уникальный идентификатор устройства (как правило в каждой операционной системе такой можно найти), от котого взяли двузначный хэш.
Кроме того очень полезным приобретением для нас оказалась следующая концепция:
Устройства и пользователи делятся на «реальных» и «тестовых». Для определения вторых мы пробовали разные (например по UDID, когда его использование запретили, по идентификатору для рекламы, но ограничения наложили и на него, да и вообще использование таких идентификаторов не исключает коллизий, что однажды реальный пользователь увидит то, что не должен), но в конце-концов остановились на простой схеме: маленькая утилита при запуске на устройстве записывает некоторый ключ в шифрованное хранилище на устройстве — такое есть на каждой мобильной системе, на iOS, например, такой является Keychain. Основное же приложение при запуске проверяет наличие этого ключа и, в случае его наличия считает пользователя тестовым.
ВАЖНО: Если вы вводите такого рода разделение, постарайтесь соблюсти две вещи:
А теперь, когда у нас были тесовые пользователи — для чего мы их использовали?
Итак, а теперь перейдем к основному сегментационному конфигу:
Он ориентирован на более прагматичные задачи — на то, что и принято в сообществе считать классическим A/B.
Этот конфиг структурирован в виде некоторого словаря (например, JSON), в формате id_фичи:{словарь параметров}.
Здесь нам уже не нужны какие-то проценты и прочие точки ветвления — как мы помним, к этому моменту мы уже зарегистрированы в системе — и, соответственно, на основе заведомо уникального user_id мы возвращаем для пользователя специфичные конкретно для него параметры, на основе имеющегося на сервере модуля сегментации. В нем мы можем опираться на:
И многие другие данные.
Для чего это используется?
Как описывалось в начале статьи — некоторую большую функциональность открывать довольно таки страшно, поэтому таким способом мы можем, во-первых, отключить фичу, которая ведет себя не так, как ожидалось. А во-вторых, обеспечить постепенное открытие этой функциональности для пользователей (открываем для 5 процентов — наблюдаем, потом для 10, 20, 50 и, наконец, для всех).
В каждую проектируемую для А/В фичу можно закладывать ряд переменных — текст на всплывающем окошке, время анимации, время между показами, цвет кнопки, один из вариантов возможного поведения. Чем больше таких параметров — тем больше можно ставить экспериментов в поиске наилучшего решения. Ограничены вы только вашей фантазией. С другой стороны — тем больший объем тестирования необходим для данной функциональности. (Правда, этот объем можно неплохо размазать по времени — протестировав основную работоспособность приложения, в дальнейшем просто проводить краткое тестирование на тестовом сервере того набора параметров, которые собираются выкатить)
Итак, резюмируя эту часть, хотелось бы отметить следующие пункты:
Спроси себя, а не фигню ли я делаю
В первой части я написал, что мы делаем, в этой же постараюсь описать — а как же нам, собственно, понять, то ли мы делаем.
Самый простой способ понять, что происходит что-то не то — это узнать, что после внедрения новой функциональности приложение просто перестало работать — начало радостно падать.
Для нее мы используем HockeyApp — потому что у него достаточно удобный инструментарий по работе с уже существующими крэшами, а, кроме того, он неплохо интегрирован в различные деплоймент-системы — так что поддерживать актуальность информации в нем можно в автоматическом режиме. Но, по факту, таких инструментов на данный момент существует весьма приличное количество — на любой вкус и цвет, выбирайте сами. Как я писал немного выше — работа с ним стала еще более приятней с того момента, как мы ввели возможность прикреплять к крэш-логу кусок из лога устройства.
Пожалуй, основной инструмент, интересующий бизнес. Для него тоже существует довольно много различных инструментов, но мы используем некоторую смесь самописного и существующего. Потому что не каждый бизнес пойдет на то, чтобы расшарить информацию о платежах со сторонними сервисами. И правильно и сделает. Существующие системы позволяют нам достаточно комфортно обнаруживать за самым краткосрочным и самым долгосрочным трендом качества приложения. При деплое существенной функциональности наблюдения заслуживают следующие метрики:
Современные сервисы позволяют неплохо сегментировать эту аналитику (по устройствам, по версиям приложения, по геолокации и еще по куче признаков), что позволяет быть более точным в своих прогнозах.
К сожалению, очень плохо формализуемый и не поддающийся автоматизации процесс, но, думаю, его важность и нужность объяснять не требуется для любых (не только больших) приложений. Хорошим тоном будет дать возможность написать какой-то отзыв-предложение непосредственно в компанию, потому что в большом количестве отзывов он может быть пропущен.
Для этого, к сожалению, не получилось найти достаточно удобный и функциональный простой публичный инструмент, поэтому этому и посвящена большая часть логов приложения и выделенный лог сервер.
Мы используем для этого Hadoop (и несколько других сервисов) по следующим причинам:
Я полагаю, все эти требования являются достаточно важными, а инструмент, который им удовлетворяет, я полагаю, не один.
И, пожалуй, самый важный пункт, следующий из наличия у вас подобного инструментария — он предоставляет возможность построения формальных (и достаточно точных) метрик для оценки качества и востребованности функциональности. Если кнопку не нажимают — ее нужно убрать, даже если она очень красива. Если после внедрения суперудобной фичи пользователи стали больше жаловаться на приложение, меньше им пользоваться, меньше платить — значит эта фича не суперудобна. И так далее.
Резюмируя все вышесказанное, хотелось бы отметить несколько следующих пунктов:
Автор: i_user
Источник [1]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/razrabotka/89110
Ссылки в тексте:
[1] Источник: http://habrahabr.ru/post/255941/
Нажмите здесь для печати.