Когда дизайнер проектирует что-то сложнее посадочной страницы, возникает необходимость в разных состояниях экранов. Чаще всего дизайнеры получают одни и те же правки: «Тут нужен лоадер» или «Как выглядит ошибка?». Полный набор состояний никогда не появляется без пинка аналитика.
Годами я наблюдаю бессмысленный пинг-понг. Дизайнер рисует экран и ждёт ревью. Аналитик через пол дня открывает ссылку и просит дорисовать состояние загрузки. Задачка висит в статусе «ин-прогресс» и не уходит в разработку. Сроки растягиваются, релизы переносится.
Проблема в том, что никто не объяснил дизайнерам, как приложение работает с данными, и как подкапотные процессы влияют на элементы интерфейса.
Этот материал для всех, кто проектирует цифровые продукты и сложные сайты. Аналитики и менеджеры, покажите статью своим дизайнерам.
Что в статье:
- Как приложение общается с сервером на примере ресторана
- Откуда появляется контент?
- Последовательные и параллельные запросы
- Синхронные и асинхронные запросы
- Обязательные и необязательные запросы
- Пагинация и пустое состояние — когда нужны?
- Ошибки: какие бывают?
- Добавление и удаление элементов — на фронте или на бэке?
- Как кэш влияет на загрузку?
- Подарок: чек-лист по состояниям интерфейса
Клиент-серверная архитектура для чайников
Любое приложение состоит из трёх основных частей: клиента, сервера и базы данных. Такая структура нужна, чтобы все сложные штуки обрабатывались на мощном сервере, а не на стареньком айфоне.
Клиент — видимая часть приложения — общается с сервером, а сервер — с базой данных путём запросов и ответов. Если мы знаем, какие на экране отправляются запросы и какие могут прийти ответы, то сможем отобразить правильные состояния интерфейса.
Архитектура на примере ресторана
Представьте, что приложение — это ресторан.
Как «пользователь» ресторана вы взаимодействуете с собственным столиком, меню и официантом. Гостевой зал — это клиент. В зале красивый интерьер, меню написано аккуратным шрифтом, а на столе заранее стоят соль с перцем и салфетки.
Вы заказываете карбонару. Официант мог бы сварить пасту прямо у вас на столе, параллельно натирая пармезан и обжаривая бекон. Такому заведению потребовалось бы 20 многоруких официантов и столы со встроенной электроплиткой. В нашем примере ресторан более менее стандартный, поэтому официант передаёт ваш заказ на кухню. Кухня — это сервер.
«Одна карбонара с двойным пармезаном» — это запрос.
Через минуту вы подзываете второго официанта и заказываете салат. Теперь два блюда готовятся параллельно. В каких-то ресторанах еду выносят в порядке готовности, в других — салат строго первым курсом.
Пока блюда готовятся, официант расчищает место на столе, ставит приборы и хлебную корзинку. Такое состояние стола как бы говорит: «Здесь скоро будет еда».
Не все блюда одинаково важны. Если кухня не приготовит салат, вы не расстроитесь. Салат — необязательное блюдо. Однако без пасты ваш обед не состоится. Паста — обязательная.
Ресторан не может приготовить любое блюдо. Вот вы просите креветки в яблочном уксусе, официант консультируется с шеф-поваром и возвращается с ответом: «Такое у нас не подают, извините» — это ошибка пользователя. А бывает, заказываешь «Цезарь» из меню, и через 15 минут выясняется, что на кухне закончились чесночные гренки. Это уже ошибка сервера.
Приложения и рестораны спроектированы людьми для людей. Процессы внутри цифрового сервиса не сильно отличаются по логике от сервиса ресторанного. Давайте теперь перейдём к интерфейсу.
Откуда взялся контент
Для начала нам необходимо понять, нужны ли странице дополнительные состояния.
Пользователь видит блоки интерфейса, наполненные контентом — текстами, картинками и видосами. Каждый блок интерфейса и каждый кусок контента — это либо хардкод, либо данные с сервера.
Хардкод — это когда программист зафиксировал элемент в коде программы. Если текст или иллюстрация хардкодная, то её содержимое неизменно. Дизайнер может расслабиться — ни о каких состояниях тут думать не надо.
Контент загружается на устройство один раз и хранится в памяти смартфона, либо в кэше браузера. В ресторанном примере хардкодом была бы скатерть, солонка с перечницей и салфетница.
Если данные на странице не хардкодные, значит требуются дополнительные состояния — загрузки, ошибки или отсутствия контента.
Последовательные и параллельные запросы
Как только мы поняли, откуда берутся данные на экране, нужно задать аналитику вопрос: «Какие здесь отправляются запросы?»
Последовательные запросы — это когда блоки экрана загружаются один за другим. Состояние каждого следующего блока зависит от состояния предыдущего. Пока все процессы не отработают, процесс не завершён, ведь данные взаимосвязаны. Последовательные запросы чаще всего отправляются при инициализации экрана.
Дизайнер показывает, что данные ещё подгружаются. Если такой запрос упал, чаще всего рисуем полноэкранную ошибку. Пользователь перезагружает экран полностью.
Параллельные запросы отправляются одновременно и не ждут завершения друг друга. Каждому блоку рисуем свой собственный лоадер — спиннер или скелетон-шиммер. Состояния ошибок так же будут индивидуальными. Пользователь перезагружает каждый блок отдельно, либо страницу полностью.
Пример: Гугл. Один блок загружается, а другие уже доступны.
Синхронные и асинхронные запросы
Синхронный запрос блокирует интерфейс. Программа выполняет особо важную операцию, поэтому мы не можем нажимать кнопки и перемещаться по приложению. Дизайнеру следует показать блокирующий экран загрузки в макетах. Чаще всего блокирующий лоадер затемняет интерфейс позади себя.
Асинхронные запросы превращают пользовательский опыт в кайф. Ничего не блокируется, и пользователь продолжает свободно пользоваться интерфейсом. Социальная сеть «Вконтакте» стала успешной во многом благодаря внедрению асинхронных AJAX-запросов.
Обязательные, необязательные и фоновые запросы
Попросите аналитика категоризировать запросы по обязательности. От этого зависит вид ошибки, которую мы покажем в случае неуспешной отправки.
Обязательный запрос отвечает за ключевое действие на экране. К обязательным относятся запросы на инициализацию данных. Если приложению не удалось точно узнать, что вот этому юзеру нужно показать вон те самые данные, то лучше не показывать ничего. Пользователь видит полноэкранную ошибку с кнопкой повторной отправки.
Необязательный запрос подгружает второстепенные данные или коллекции элементов. Например, приложение запрашивает список сториз в приложении социальной сети. Если сторьки не загрузились, ничего страшного. Пользователь видит остальной контент, а проблемный блок иногда скрывают из интерфейса.
Фоновый запрос проходит за кулисами и не мешает основному пользовательскому сценарию. Когда такой запрос падает, мы чаще всего не показываем ничего. В некоторых случаях пользователь видит снек.
Пример: не получилось загрузить историю.
Пагинация и пустое состояние
Почти любая коллекция контента — фотки в инсте, проекты в Фигме, видосы на Ютубе — подгружается порциями. В противном случае пришлось бы грузить тысячи единиц контента за раз, и мы бы никогда не дождались окончания загрузки.
Каждая новая пачка контента начинает загружаться по триггеру. Пользователь промотал экран с фоточками до конца — нужно показать ему ещё. Отправляем запрос на ещё 10 фотографий.
Пагинация подразумевает состояние загрузки в том месте, где пользователь ожидает увидеть новый контент. Дизайнер может пойти простым путём и использовать стандартный спиннер. Более продвинутые ребята показывают схематичные прямоугольники и кружочки, которые говорят: «мы тут придерживаем местечко для чего-то более интересного».
В примере ниже мы видим одновременно пагинацию — колёсико загрузки — и отдельный запрос на обложки для видео, которые сейчас представлены серыми прямоугольниками — скелетонами. Это два параллельных необязательных запроса.
Дизайнеру всегда следует помнить, что контента может и не быть. Пользователь мог не успеть добавить товары в «Избранное» или не начал ни одной переписки в «Мессенджере».
Пустое состояние (англ. Empty State) говорит юзеру: «Здесь пока пусто, добавь что-нибудь». Можем показать эмпти-стейт после загрузки, а можем — моментально, если знаем заранее, что контент отсутствует.
Pull-to-Refresh — это когда пользователь тянет экран мобильного приложения вниз для перезагрузки. ПТР отправляет запросы на обновление всех данных на экране.
Пример: все графики на кадшборде обновляются одним ПТР-ом.
Ошибки: типичные и специфические
Ошибки бывают типовые и специфические. Разобраться со первыми вам поможет аналитик или разработчик, а мы в рассмотрим несколько базовых.
Нет интернета. Если отвалилась сеть во время загрузки, показываем пользователю полноэкранную заглушку. Можем добавить иллюстрацию для наглядности — грустный вайфай или разорванные провода — на ваш вкус.
Не нужно перекрывать экран при каждом обрыве связи. Соединение возобновится через 10 секунд, а терпение юзера — нет. Чатик в Телеграме или маршрут в Яндекс Гоу информируют о состоянии сети маленькой подписью.
Проблемы на сервере. Пользователям не интересно, что происходит у нас с сервером. Нужно дать человеку понять, что ошибка на нашей стороне и предложить логичные дальнейшие шаги.
Тайм-аут. Запросу выделяется фиксированное время на отправку, обычно 10–15 секунд. Если запрос не отработал в указанное время, приложение может отправить его повторно «за кулисами», либо сообщить о проблеме юзеру. В первом случае можем написать, что процесс выполняется дольше обычного. Во втором случае дизайнер рисует состояние с кнопкой повторной отправки.
Ошибки валидации. Каждая форма проверяется скриптом на правильность заполнения. Если пользователь не заполнил обязательное поле, либо заполнил его неверными данными, интерфейс должен об этом сообщить.
Удаление и добавление элементов
Добавление, удаление и изменение порядка элементов проходит либо на клиенте, либо на сервере. От этого зависит, в какой момент покажем загрузку.
Если редактирование медиафайлов происходят на клиенте, даём юзеру полную свободу — пусть играется с картинками беспрепятственно. Потребуется одно состояние загрузки — в момент сохранения.
Если фотки меняются на сервере, демонстрируем лодер при каждом изменении медиа-контента. Придётся блокировать интерфейс управления контентом, пока не получим положительный ответ с сервера.
Не забываем про состояния ошибок. Рисуем их по одной логике с лоадерами.
Кэширование
Последнее, что нужно узнать у системного аналитика — кэшируются ли данные на экране, и в какой момент мы их актуализируем.
Пример. Лента Инсты кэшируется. Телефон хранит фотки с прошлой сессии. Пользователь открывает приложение и вместо серых квадратиков видит реальные фотографии. Фоном идёт запрос новой пачки контента.
Дизайнеру нужно продумать все возможные сценарии:
— Сколько постов хранить в кэше?
— Что будет, когда пользователь долистает список до конца?
— Как покажем проблемы с интернетом?
— Куда подвинем старые фотографии в момент получения новых?
— Нужно ли промежуточное состояние загрузки?
— Что будет, если пользователь попробует обновить экран самостоятельно?
— …
Подытожим
Мы разобрались с устройством клиент-серверного взаимодействия, познакомились с запросами и прошлись по типичным интерфейсным состояниям.
Статья не покрывает всех возможных кейсов. Не бойтесь задавать вопросы команде.
Подарок
Собрал чек-лист по состояниями интерфейса. Простой список поможет проверить макеты на наличие необходимых экранов. Документ можно пошерить младшим дизайнерам, чтобы не писать по десять комментов к каждой задачке.
Чек-лист лежит в моём телеграм-канале. Забирайте, пока бесплатно.
Обсуждение
Похожее
Мини-курс по дизайн-системе мобильного приложения
Google Keep — новый заметочно-тудушный сервис.
PSD компоненты для плоского UI