Оффтоп Лена Очкова
5 117

Кейс: Как создавалось новое приложение «Афиши»

19 ноября «Афиша» выпустила первое обновление своего iOS-приложения за последние несколько лет. Оно получило новый дизайн, интерфейсные решения и функции.

Команда, работавшая над проектом, рассказала vc.ru о процессе работы над приложением.

О старом приложении

Приложение «Афиши» существует уже очень давно: выпущено оно было в 2009 году и с тех пор практически не менялось. Несмотря на это, аудитория предыдущей версии приложения до последнего дня его существования составляла более 500 тысяч пользователей в месяц.

Предыдущая версия была хороша для 2009-2010 года, а дальше она стала морально и технологически устаревать — как и дизайн, который на фоне все более креативных интерфейсов топовых приложений стал выглядеть скучно и даже безлико.

О новом UX

Основная задача, которую нам необходимо было решить в кратчайшие сроки, — сделать приложение современным, быстрым, стабильным и простым. Сделать так, чтобы «Афиша» действительно стала афишей: пользователи уже на входе в приложение должны получать актуальную информацию о самых интересных событиях, которые происходят в их городе.

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

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

Первое впечатление

При входе в приложение показывается список популярных событий в городе на сегодня. Большие и красивые картинки выглядят привлекательнее, чем список с категориями. Здесь же сразу можно увидеть краткое описание, место проведения и рейтинг события.

Важными сценариями для нас были покупка билетов и бронирование столиков, поэтому мы вынесли кнопки с этими контролами сразу в список. Многие пользователи четко знают, куда хотят купить билет — например, на новые «Голодные игры», — и им совсем не нужен лишний переход на экран с информацией о фильме.

Еще одним важным сценарием был поиск по огромной базе «Афиши». Метрики показали, что поиском в приложении пользовались крайне редко, что и неудивительно: он был спрятан в разделе «Еще», на отдельном экране. Теперь он стоит на главной — там, где и должен быть.

Также было принято решение избавиться от нижнего бара с переключением на другие разделы, так как подавляющее большинство людей пользуется только разделами «Главная» или «Сегодня». «Избранное» и «Я пойду» были не особенно популярны у пользователей приложения. Было принято решение переработать функцию «Я пойду» и на время первого релиза вовсе ее убрать. А вот «Избранное» мы немного модифицировали, и на выходе получилась вкладка «Мне нравится», которую мы поделили на два логических блока — события и места.

Еще нам хотелось сделать процесс скролла списка интересным, с настроением — и мы добавили необычную анимацию «сжатия» верхнего бара, чтобы концентрация пользователя на контенте становилась максимальной: никаких лишних контролов, отъедающих место на экране, только афиша.

Информативность

Информация о фильмах, спектаклях, концертах и местах — это та сфера, в которой «Афиша» всегда была одним из передовых игроков рынка, поэтому экран со списками событий был полностью изменен. Для каждого вида события и места был разработан свой layout, порядок информации и логика отображения контента. В ближайших планах — добавление в карточки событий, мест расписаний и сеансов.

В карточках событий и мест хотелось отойти от канонов дизайна iOS и сделать его более «книжным» и удобным для целевых действий — вынесли рейтинг на самое видное место карточки и поместили кнопку покупки вниз во всю ширину экрана: даже если захочешь, не промахнешься. Тут мы тоже не забыли добавить приятную анимацию, которая задает настроение всему приложению.

Простота

Навигация в приложении крайне проста и привычна. На главном экране есть два меню: основное левое, в котором располагаются категории событий и мест и профиль, и правое с выбором временного диапазона. Фильтры по датам были спрятаны в отдельное меню: пользователей чаще интересуют ближайшие события, заданные фильтром по умолчанию. Это позволило сохранить основное меню простым, с возможностью быстрого доступа к любому интересующему разделу.

В профиле находятся малоиспользуемые разделы, такие как история своих просмотров, события и места, которые вам понравились, и техническая информация приложения.

Билеты теперь хранятся внутри приложения. Из-за ряда технических сложностей и ограничений нам пришлось добавить этот важный раздел в профиль, но это не помешало сделать его красивым и информативным.

Признаться, корректность расположения профиля до сих пор вызывает у нас некоторые сомнения, поэтому в ближайшем релизе мы, вероятно, изменим путь к нему.

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

Команда

iOS-команда «Афиши» небольшая: три мобильных разработчика, два серверных разработчика, дизайнер, тестировщик и руководитель проекта.

Процесс разработки

Вся работа строилась на столпах гибких Agile-методологий, и каждый из команды всегда четко знал, кто и что делает, когда будет выполнена та или иная задача, что будет дальше и когда вообще все закончится. Контрольными точками по сверке часов были регулярные встречи и выпуск билдов по окончании каждого двухнедельного спринта.

Спринты разных участников команды были сдвинуты относительно друг друга таким образом, чтобы на момент начала работы iOS-команды функциональность была уже готова: техническое задание составлено, макеты согласованы и соответствующая функциональность бэкенда (API) написана. Каждый билд передавался на тестирование и верификацию дизайнером.

Найденные тестировщиком и дизайнером ошибки переходили в следующую итерацию разработки.

Инструменты, которые мы использовали

Jira — постановка задач, учет сроков. Классический инструмент для организации работы над проектом. Мы оформили рабочее пространство Jira таким образом, чтобы в нем были задействованы все участники проекта. Крупные фичи оформлялись эпиками и могли включать задачи на дизайн, бэкенд и iOS-разработку. У задач были статусы: ToDo, In Progress, Ready for test, Testing, Tested, Resolved, Done. Такое разделение было сделано, потому что новые билды выходили относительно часто, и было необходимо отслеживать, какие задачи и багфиксы вошли в билд, который в тестировании, а какие нет.

Confluence — база знаний проекта, документация и техническое задание.

Zeplin — программа для автоматической генерации разметки по макетам из Sketch. Ее использование сэкономило огромное количество времени дизайнеру, которому не нужно было специальным образом размечать отступы, шрифты и цвета на макетах.

Form — для описания анимаций математической моделью. Аналог Quartz composer, который позволяет разработчику легко реализовывать анимации по заданным параметрам, а не мучительно подбирать их длительность, силу и упругость по видео. Все, что нужно, — научить дизайнера творить именно в этой программе.

Практики, которые мы применяли

Relative mass evaluation (относительная массовая оценка)

В какой-то момент бэклог проекта начал неуправляемо разрастаться и было необходимо быстро и адекватно оценить большое количество задач. Тогда мы и решили применить метод относительной оценки. Работает это так: для каждой задачи мы сделали бумажную карточку. Затем разложили все эти карточки на просторном столе, последовательно перебрали и расположили по порядку от самой легкой к самой сложной. После того как мы оценили все задачи относительно друг друга, несложно было присвоить временные оценки самой сложной и самой легкой задачам, а далее линейно распространить оценку на остальные. Чем больше задач, тем выгоднее по времени такой способ оценки.

Публичное тестирование

За месяц до релиза было проведено публичное тестирование бета-версии приложения. Фокус-группой являлась вся компания Rambler&Co. Это позволило выявить как баги, так и проблемы с UX.

Особенности технической части

Со времени разработки новой версии приложения многое изменилось: платформа пережила несколько обновлений, принципы и подходы к разработке мобильных приложений в «Рамблере». Поэтому было принято решение написать все с чистого листа. Необходимо было сделать универсальное приложение (iPhone + iPad) с поддержкой версий операционной системы, начиная с iOS 7.

При разработке команда уделила особое внимание качеству и выполнила следующие важные действия:

  • Спроектировала архитектуру приложения перед стартом разработки;
  • Вела разработку итеративно с выдачей билда в тестирование каждые две недели;
  • Писала бизнес-логику по технике test driven development (разработка через тестирование) и имела полное покрытие тестами;
  • Прогоняла приложение на выделенном сервере Jenkins с подсчетом количества тестов и процента покрытия кода (continuous integration);
  • Проводила code review и обсуждала принятые архитектурные решения.

Метрики программного продукта:

  • количество строк кода (без сторонних библиотек) — 31043;
  • количество коммитов в git — 2359;
  • количество багов на 1000 строк кода — 1,5;
  • процент покрытия кода тестами — 52%;
  • количество выпитых литров кофе подсчитать не удалось.

#Интерфейсы #афиша #Rambler_Co #Разработка_приложений #приложение_афиши

Материал опубликован пользователем. Нажмите кнопку «Написать», чтобы поделиться мнением или рассказать о своём проекте.

Написать
{ "author_name": "Лена Очкова", "author_type": "self", "tags": ["\u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0430_\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439","\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435_\u0430\u0444\u0438\u0448\u0438","\u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u044b","\u0434\u0438\u0437\u0430\u0439\u043d","\u0430\u0444\u0438\u0448\u0430","rambler_co"], "comments": 15, "likes": 14, "favorites": 1, "is_advertisement": false, "subsite_label": "flood", "id": 11927, "is_wide": true }
00
дни
00
часы
00
мин
00
сек
(function(){ var banner = document.querySelector('.teaserSberbank'); var isAdsDisabled = document.querySelector('noad'); if (!isAdsDisabled){ var countdownTimer = null; var timerItem = document.querySelectorAll('[data-sber-timer]'); var seconds = parseInt('15388' + '59599') - now(); function now(){ return Math.round(new Date().getTime()/1000.0); } function timer() { var days = Math.floor(seconds / 24 / 60 / 60); var hoursLeft = Math.floor((seconds) - (days * 86400)); var hours = Math.floor(hoursLeft / 3600); var minutesLeft = Math.floor((hoursLeft) - (hours * 3600)); var minutes = Math.floor(minutesLeft / 60); var remainingSeconds = seconds % 60; if (days < 10) days = '0' + days; if (hours < 10) hours = '0' + hours; if (minutes < 10) minutes = '0' + minutes; if (remainingSeconds < 10) remainingSeconds = '0' + remainingSeconds; if (seconds <= 0) { clearInterval(countdownTimer); } else { timerItem[0].textContent = days; timerItem[1].textContent = hours; timerItem[2].textContent = minutes; timerItem[3].textContent = remainingSeconds; seconds -= 1; } } timer(); countdownTimer = setInterval(timer, 1000); } else { banner.style.display = 'none'; } })();
{ "id": 11927, "author_id": 32927, "diff_limit": 1000, "urls": {"diff":"\/comments\/11927\/get","add":"\/comments\/11927\/add","edit":"\/comments\/edit","remove":"\/admin\/comments\/remove","pin":"\/admin\/comments\/pin","get4edit":"\/comments\/get4edit","complain":"\/comments\/complain","load_more":"\/comments\/loading\/11927"}, "attach_limit": 2, "max_comment_text_length": 5000, "subsite_id": 199791 }

15 комментариев 15 комм.

Популярные

По порядку

Написать комментарий...
1

А что по срокам? Сколько делали?

Ответить
5

Разработка с нуля заняла у нас 5 месяцев.

Ответить
0

Круто. Тех. вопрос. А использовали Size Classes для разработки интерфейса приложения?

Ответить
0

2015 год
в приложении нет ни одного свайпа...

Ответить
2

Переключатель с низу вапще жесть..

Ответить
1

и святую святых убрали - избранное.. каждый раз теперь чтоли кинотеатр из списка искать..

Ответить
0

Избранное есть, но теперь называется «Мне нравится» + еще есть «История»)

Ответить
2

и еще спасибо за "удобное" расписание сеансов..

Ответить
0

Все будет!

Ответить

Комментарий удален

0

А есть приложения которые смогут прототип загнать сразу в xcode? А тоьв Form и Pixate такого нет :C

Ответить
0

Теперь вообще нет смысла смотреть расписание сеансов, так как оно гарантировано не полное. Показываются только кинотеатры, в которые Афиша может продать билет. :(

Ответить
0

А длЯ Андроида, когда обновился (до этого уровня)?!.

Ответить
0

РАСПИСАНИЕ СЕАНСОВ В КИНОТЕАТРАХ ГДЕ???

Ответить
0

1. Выбрал на главной красивую картинку с кино — расписание сеансов нету
2. Перешел в 'кино на сегодня' — пишут "нет событий на сегодня"
3. Ушел в кинотеатр — там можно найти расписание, но через кассу.
4. На главной нажал на 'five years of rodnya' - "что-то не заработало" ; то же с гиперболойдом
5. Кинотеатры ближайшие - поиск только по карте, тут моя вкусовщина, коненчо в чистом виде, но я списком люблю смотреть, кто рядом
6. Поиск события / места разделен - дело привычки, конечно, но вообще вы бы и сами за меня могли понимать заведение / ресторан я ищу и предлагать мне его повыше в саджесте.

Приложение-то симпатичное и обновление в целом правильное, косяки подлатать всегда можно, но не понятно зачем столько пиара, когда серверная часть еще не заончена и ошибки есть детские.
Ну и вообще API у вас как-то долго думает (

Ответить
0

1. Выбрал на главной красивую картинку с кино — расписание сеансов нету
2. Перешел в 'кино на сегодня' — пишут "нет событий на сегодня"
3. Ушел в кинотеатр — там можно найти расписание, но через кассу.
4. На главной нажал на 'five years of rodnya' - "что-то не заработало" ; то же с гиперболойдом
5. Кинотеатры ближайшие - поиск только по карте, тут моя вкусовщина, коненчо в чистом виде, но я списком люблю смотреть, кто рядом
6. Поиск события / места разделен - дело привычки, конечно, но вообще вы бы и сами за меня могли понимать заведение / ресторан я ищу и предлагать мне его повыше в саджесте.

Приложение-то симпатичное и обновление в целом правильное, косяки подлатать всегда можно, но не понятно зачем столько пиара, когда серверная часть еще не заончена и ошибки есть детские.
Ну и вообще API у вас как-то долго думает (

Ответить
0

Прямой эфир

[ { "id": 1, "label": "100%×150_Branding_desktop", "provider": "adfox", "adaptive": [ "desktop" ], "adfox_method": "createAdaptive", "auto_reload": true, "adfox": { "ownerId": 228129, "params": { "pp": "g", "ps": "bugf", "p2": "ezfl" } } }, { "id": 2, "label": "1200х400", "provider": "adfox", "adaptive": [ "phone" ], "auto_reload": true, "adfox": { "ownerId": 228129, "params": { "pp": "g", "ps": "bugf", "p2": "ezfn" } } }, { "id": 3, "label": "240х200 _ТГБ_desktop", "provider": "adfox", "adaptive": [ "desktop" ], "adfox": { "ownerId": 228129, "params": { "pp": "g", "ps": "bugf", "p2": "fizc" } } }, { "id": 4, "label": "240х200_mobile", "provider": "adfox", "adaptive": [ "phone" ], "adfox": { "ownerId": 228129, "params": { "pp": "g", "ps": "bugf", "p2": "flbq" } } }, { "id": 5, "label": "300x500_desktop", "provider": "adfox", "adaptive": [ "desktop" ], "adfox": { "ownerId": 228129, "params": { "pp": "g", "ps": "bugf", "p2": "ezfk" } } }, { "id": 6, "label": "1180х250_Interpool_баннер над комментариями_Desktop", "provider": "adfox", "adaptive": [ "desktop" ], "adfox": { "ownerId": 228129, "params": { "pp": "h", "ps": "bugf", "p2": "ffyh" } } }, { "id": 7, "label": "Article Footer 100%_desktop_mobile", "provider": "adfox", "adaptive": [ "desktop", "tablet", "phone" ], "adfox": { "ownerId": 228129, "params": { "pp": "g", "ps": "bugf", "p2": "fjxb" } } }, { "id": 8, "label": "Fullscreen Desktop", "provider": "adfox", "adaptive": [ "desktop", "tablet" ], "auto_reload": true, "adfox": { "ownerId": 228129, "params": { "pp": "g", "ps": "bugf", "p2": "fjoh" } } }, { "id": 9, "label": "Fullscreen Mobile", "provider": "adfox", "adaptive": [ "phone" ], "auto_reload": true, "adfox": { "ownerId": 228129, "params": { "pp": "g", "ps": "bugf", "p2": "fjog" } } }, { "id": 10, "disable": true, "label": "Native Partner Desktop", "provider": "adfox", "adaptive": [ "desktop", "tablet" ], "adfox": { "ownerId": 228129, "params": { "pp": "g", "ps": "clmf", "p2": "fmyb" } } }, { "id": 11, "disable": true, "label": "Native Partner Mobile", "provider": "adfox", "adaptive": [ "phone" ], "adfox": { "ownerId": 228129, "params": { "pp": "g", "ps": "clmf", "p2": "fmyc" } } }, { "id": 12, "label": "Кнопка в шапке", "provider": "adfox", "adaptive": [ "desktop" ], "adfox": { "ownerId": 228129, "params": { "p1": "bscsh", "p2": "fdhx" } } }, { "id": 13, "label": "DM InPage Video PartnerCode", "provider": "adfox", "adaptive": [ "desktop", "tablet", "phone" ], "adfox_method": "createAdaptive", "adfox": { "ownerId": 228129, "params": { "pp": "h", "ps": "bugf", "p2": "flvn" } } }, { "id": 14, "label": "Yandex context video banner", "provider": "yandex", "yandex": { "block_id": "VI-223676-0", "render_to": "inpage_VI-223676-0-1104503429", "adfox_url": "//ads.adfox.ru/228129/getCode?pp=h&ps=bugf&p2=fpjw&puid1=&puid2=&puid3=&puid4=&puid8=&puid9=&puid10=&puid21=&puid22=&puid31=&puid32=&puid33=&fmt=1&dl={REFERER}&pr=" } }, { "id": 15, "label": "Плашка на главной", "provider": "adfox", "adaptive": [ "desktop", "tablet", "phone" ], "adfox": { "ownerId": 228129, "params": { "p1": "byudx", "p2": "ftjf" } } }, { "id": 16, "label": "Кнопка в шапке мобайл", "provider": "adfox", "adaptive": [ "tablet", "phone" ], "adfox": { "ownerId": 228129, "params": { "p1": "byzqf", "p2": "ftwx" } } }, { "id": 17, "label": "Stratum Desktop", "provider": "adfox", "adaptive": [ "desktop" ], "auto_reload": true, "adfox": { "ownerId": 228129, "params": { "pp": "g", "ps": "bugf", "p2": "fzvb" } } }, { "id": 18, "label": "Stratum Mobile", "provider": "adfox", "adaptive": [ "tablet", "phone" ], "auto_reload": true, "adfox": { "ownerId": 228129, "params": { "pp": "g", "ps": "bugf", "p2": "fzvc" } } }, { "id": 19, "label": "Тизер на главной", "provider": "adfox", "adaptive": [ "desktop", "tablet", "phone" ], "auto_reload": true, "adfox": { "ownerId": 228129, "params": { "p1": "cbltd", "p2": "gazs" } } } ]
Голосовой помощник выкупил
компанию-создателя
Подписаться на push-уведомления