{"id":14275,"url":"\/distributions\/14275\/click?bit=1&hash=bccbaeb320d3784aa2d1badbee38ca8d11406e8938daaca7e74be177682eb28b","title":"\u041d\u0430 \u0447\u0451\u043c \u0437\u0430\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u044e\u0442 \u043f\u0440\u043e\u0444\u0435\u0441\u0441\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u044b\u0435 \u043f\u0440\u043e\u0434\u0430\u0432\u0446\u044b \u0430\u0432\u0442\u043e?","buttonText":"\u0423\u0437\u043d\u0430\u0442\u044c","imageUuid":"f72066c6-8459-501b-aea6-770cd3ac60a6"}

Как сократить количество исправлений дизайна на этапе разработки: наш опыт

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

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

Из-за каких ошибок приходится переделывать UI и UX

Основная ошибка, с которой мы сталкиваемся при разработке пользовательского интерфейса и опыта любого веб- или мобильного приложения, — мы прорабатываем основной сценарий, но забываем про краевые сценарии. Из-за этого основной может зайти в тупик или положить всё приложение.

Почему так происходит

Чтобы качественно и полноценно спроектировать пользовательский интерфейс и опыт, учитывая при этом все краевые сценарии, при проектировании важно уточнить:

  1. Обмениваемые данные между клиентом и сервером.

  2. События, после которых должны обновляться данные на экранах.

  3. Контекст экранов (одни экраны должны демонстрировать пользователю контент, вторые — собирать данные от пользователя, третьи — показывать загрузки и т. д.).

Для этого аналитику важно понимать:

  • что такое система,

  • как строится архитектура,

  • как работает клиент-серверное взаимодействие,

  • что такое API,

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

Разберём каждое из этих понятий и посмотрим на примерах, как можно обработать ответы сервера — и избежать десятков итераций исправлений дизайна на более поздних этапах реализации.

Что лежит под капотом любого приложения

Система

Это множество взаимосвязанных элементов. Обычно на этапе проектирования целевая задача системы декомпозируется на подсистемы. За каждым элементом закрепляется функциональная зона — это значительно упрощает понимание будущего продукта и процесс его разработки. В результате архитектор или backend-разработчик проектирует системную архитектуру, дающую представление об элементах и их взаимосвязях в будущем продукте.

Архитектура

Основополагающие элементы любой архитектуры — это Frontend, Backend и база данных.

Описание взаимодействия Frontend, Backend и базы данных
  1. Frontend — это интерфейс, с помощью которого пользователь взаимодействует с системой. Проектируя макеты, дизайнеры создают именно интерфейс и пользовательский опыт.

  2. Backend — это «чёрный ящик» с основной логикой системы. Дотянуться до него и взаимодействовать с ним напрямую пользователь не может.

Если Backend работает с данными, то они хранятся в соответствующей базе. Она выполняет с ними минимальные действия — добавление, чтение, обновление, удаление и другие, а также, что очень важно, защищает в случае сбоя.

Не стоит забывать и о промежуточных компонентах архитектуры. Они могут существовать между элементами системы или другими системами. Например, брокеры сообщений преобразуют данные из одной структуры в другую, обычно только в одном процессе. Шины данных делают примерно то же самое, но покрывают сразу несколько процессов и часто имеют в своей основе брокер сообщений.

Клиент-серверное взаимодействие

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

Существует несколько типов клиент-серверной архитектуры. Ниже представлена двухуровневая — она состоит из клиента и сервера.

Клиент — это приложение, с помощью которого человек может пользоваться функциями, реализованными на сервере. А сервер — мощный «чёрный ящик» с основной логикой.

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

Посмотрим на примере стандартного процесс взаимодействия клиента и сервера:

  1. Клиент инициирует подключение, пока сервер его терпеливо ждёт.

  2. Клиент формирует запрос, наполняя его требуемыми данными, и отправляет на сервер.

  3. Сервер получает запрос клиента и обрабатывает его, понимая, что нужно клиенту.

  4. Сервер генерирует соответствующий ответ и отправляет его клиенту.

  5. Клиент получает ответ и обрабатывает его.

Код ответа сервера — это трёхзначные коды, объединённые в несколько классов. По коду, который возвращается от сервера, можно определить, что произошло с запросом. Например, в протоколах HTTP и HTTPS ответы принято объединять в классы кодов состояний, которые можно определить по первой цифре:

  • 1×× — информационные,

  • 2×× — успешные запросы,

  • 3×× — перенаправления,

  • 4×× — ошибки клиента,

  • 5×× — ошибки сервера.

Взаимодействие, или «общение» между системами

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

Прежде всего, они делают это, чтобы получать данные, необходимые для обработки и использования. А в некоторых случаях — чтобы отправлять данные другим системам, например, для их обработки на стороне или последующего использования.

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

Итак, мы разобрались с основными техническими понятиями — системой, архитектурой, клиент-серверным взаимодействием и API. Теперь посмотрим примеры и разберём, как можно обрабатывать основные и краевые сценарии, чтобы учесть обмен данными и выстроить правильную последовательность экранов.

Обработка ответов сервера

Успешный запрос

Данные приходят полностью и в установленный промежуток времени.

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

  1. Shimmer — анимационный эффект мерцания. Представляет собой «скелет», визуально похожий на будущий контент.

  2. Preloader — анимированный графический элемент. Показывается до того, как данные полностью загрузятся.

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

В приложении для сети заправок «Нефтьмагистраль» во время обработки запроса на получение данных используется Shimmer и только после ответа сервера выводятся данные
В приложении по оформлению командировок для сотрудников «Норникеля» во время загрузки данных используется Preloader
В приложении «Ростелеком Ключ» на время обработки запроса на оплату покупки пользователю также показывается Preloader

В примере выше в случае неуспешного выполнения запроса отображается ошибка с возможностью повторить оплату.

Разберём, какие бывают возможные ошибки сервера и на примере проектов red_mad_robot покажем варианты их обработки в дизайне.

Перенаправление запросов

Для понимания причин возникновения краевых сценариев стоит обратить внимание на то, что запросы могут перенаправляться. Это временные или постоянные меры, вызванные изменением адреса ресурсов, элементов системы и т. д.

При проектировании UI/UX важно учитывать время обработки запроса и сообщать пользователю, что необходимо подождать. То есть с клиента отправляется запрос на сервер, а тот отвечает ему: «Ожидайте». Обычно сервер не может сообщить, сколько именно придётся ждать. Поэтому нужно продумать рациональное количество времени ожидания, после которого пользователю будет демонстрироваться ошибка.

Ниже на примерах показаны варианты обработки различных ошибок клиента и сервера, включая ошибки, связанные с перенаправлением запросов.

Ошибки клиента

За ошибки клиента отвечают оба участника соединения: и клиент, и сервер. К ошибкам со стороны клиента можно отнести:

  • отправляется неправильный запрос (400),

  • «протух» токен авторизации (401),

  • недостаточно прав на использование сервиса или функции (403),

  • запрошенный ресурс уже не существует (404).

При возникновении ошибки нужно показать её пользователю и объяснить дальнейшие шаги для её устранения.

В приложении для компании НЛМК при возникновении ошибки клиента 401 Unauthorized мы подсказываем пользователю, что необходимо заново пройти авторизацию
В облачном хранилище при отсутствии прав доступа к файлам сообщаем пользователю, что нужно обратиться к владельцу запрашиваемых файлов

В нашей практике мы стараемся закладывать значения и описание ошибок на Backend, чтобы Frontend мог правильно определить причину ошибки и отобразить её для пользователя в читабельном виде.

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

Google отображает пользователю ошибку и всеми известный код 404

Отдельно стоит выделить ошибку, связанную с отсутствием интернет-соединения, которая лежит на стороне клиента.

Пример отображения сообщения пользователю об отсутствии интернет-соединения

Ошибки сервера

Основная ошибка сервера — ему отправляются запросы, а он «лежит».

Единственный выход — ждать, когда сервер поднимется. А пока нужно сообщить пользователю о проблеме и попросить его повторить действие позднее.

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

В приложении при возникновении ошибки сервера говорим о ней пользователю и просим его повторить действие позднее или связаться с поддержкой

На экранах ниже приведены различные варианты обработки ошибок сервера.

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

Все краевые сценарии, о которых мы говорили выше, особенно важны для прорисовки. Это позволит исключить вероятность возникновения тупиковых ситуаций в UX.

Работа с данными

Кэширование и протокол Websocket — обе технологии требуют особого внимания на ранних этапах проектирования системы, потому что могут значительно влиять на UI и UX.

Кэш

Несмотря на привлекательность кэширования данных, использовать эту технологию нужно аккуратно.

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

В приложении для сети заправок «Нефтьмагистраль» после первой загрузки данных кэшировалась информация о бонусах пользователя. При обновлении в случае ошибки мы показываем пользователю информацию и говорим, что действие необходимо повторить. Если бы мы не кэшировали данные, то пользователь видел бы полноэкранную ошибку
В этом же проекте мы кэшировали QR-код для начисления бонусов. Бывало, что где-то на трассе нет интернета и без кэширования пользователь не мог загрузить код при оплате на заправке и, следовательно, накопить бонусы. Поэтому мы решили кэшировать этот код

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

Websocket

Отдельное внимание стоит обратить на протокол Websocket и ему подобные: gRPC, AMQP, библиотека Socket.IO. Главное отличие от синхронного взаимодействия (о нём подробно поговорим чуть позже) в том, что не только клиент может слать запросы серверу, но и сервер может отправлять данные клиенту в любой момент, пока открыто соединение.

Между системами выстраивается канал (Ping-Pong) — обмен данными происходит практически мгновенно. Отличный пример использования Websocket — получение данных о балансе. Как мы уже говорили, пользователю всегда важно знать точное значение суммы на счёту.

Справедливый вопрос: почему бы тогда не использовать Websocket везде, если это так удобно? Чтобы на него ответить и определить правила применения этой технологии, нужно познакомиться с понятиями синхронного и асинхронного взаимодействия.

Ошибка, возникающая при разрыве соединения, в чате, реализованном с применением технологии Websocket

Синхронное и асинхронное взаимодействие

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

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

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

Синхронное и асинхронное взаимодействие

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

Зачем так сделано? Правильно, это удобно! Вспомним реализацию социальных сетей много лет назад. Чтобы понять, отправил ли тебе что-то собеседник, нужно было обновить страницу. Особое неудобство это вызывало в групповых чатах — задавая вопрос и обновляя страницу, мы могли обнаружить уже десяток полученных сообщений и среди них — возможный ответ на свой вопрос. Это и есть показательный пример синхронного взаимодействия — для обновления данных в системе требовалось дополнительное действие.

Ещё один пример — системы по сбору данных и расчётов, например ОСАГО. Параметры вводятся в калькулятор, после нажатия кнопки происходит загрузка. И во время этой загрузки пользователь не может вводить новые параметры или запускать расчёт повторно — его действия блокируются, он должен ждать.

Так почему же нельзя везде использовать Websocket?

  1. Дело в том, что это всегда асинхронное взаимодействие, которое попросту не везде необходимо, — пользователю может мешать постоянное обновление данных. Когда нам необходимо обновлять данные часто, но не ежесекундно, можно воспользоваться поллингом — отправкой запросов через заданный временной интервал (каждые пять, десять секунд, минуту и т. д.).

  2. Данный протокол более восприимчив к кратковременным разрывам сети, из-за постоянной поддержки соединения в рабочем состоянии. Необходимо это учитывать при проектировании мобильного приложения, зависимого от подключения к сети.

  3. Websocket требует дополнительной инфраструктуры на сервере.

Для взаимодействия пользователя с системой используются UI элементы. Пользователь, взаимодействуя с UI элементами, вызывает отправку запроса на сервер (синхронно или асинхронно), поэтому сценарий работы с UI элементами очень важно учитывать при проектировании.

На примере ниже мы выделили список UI элементов в одну большую группу, т. к. их объединяет возможность предоставления выбора для пользователя. Обычно при выборе пользователем значения запрос на сервер отправляется не сразу, т. е. асинхронно.

UI-элементы, предоставляющие выбор пользователю

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

Запросы могут отправляться практически на любое действие пользователя, но есть UI-элементы, которые созданы именно для вызова событий на обновление данных.

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

UI-элементы, которые вызывают события на обновление данных

Когда не нужно отправлять запрос на сервер

Отдельно выделим обработку ошибок, не требующих получения ответа со стороны сервера. Например, сравнение значений или валидацию полей — всё это происходит на Frontend.

Если в процессе изменения паролей они не совпадают друг с другом, подсказываем пользователю, что нужно проверить введённые данные

Полученные данные с сервера могут отображаться в приложении где угодно — в зависимости от типов данных и спроектированного UI. Поэтому при проектировании необходимо:

  1. Учитывать соответствие UI-элементов и типов данных.

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

  3. Выводить подсказки в сценариях получения ошибки (клиента или сервера), а также блокировать (хотя бы частично) дальнейшее взаимодействие пользователя с системой или уведомлять пользователя о необходимости повторного выполнения действия.

  4. Выводить пользователю уведомление после долгой загрузки данных в сценариях, когда время ожидания ответа превышено.

Заключение

Мы разобрали основные проблемы при проектировании UI и UX, а ещё — технические моменты, влияющие на эти проблемы, с которыми мы часто сталкивались на различных проектах.

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

Дарья Князева, старший дизайнер интерфейсов red_mad_robot

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

Анастасия Нечкина, дизайнерка интерфейсов red_mad_robot

Особое внимание при проектировании интерфейсов будущей системы нужно акцентировать на:

  • обмениваемых данных между клиентом и сервером,

  • событиях, после которых происходит обновление или загрузка данных,

  • краевых сценариях, которые нужно прорабатывать заранее.

В следующей статье более подробно расскажем о том, как аналитики и дизайнеры взаимодействуют друг с другом в процессе проектирования, так что stay tuned!

Если наш опыт оказался полезным, а тебе было интересно читать, что сгенерировали наши нейросети, посмотри ещё и статью, где мы рассказываем о том, как развиваем наши Telegram-каналы по методике кайдзен и набираем подписчиков без рекламы.

Чтобы ничего не пропустить, следи за развитием цифры вместе с нами:

VK

Да пребудет с тобой сила роботов! 🤖

0
7 комментариев
Написать комментарий...
Antny Slmv

Пупсики, статья очень крутая, что тут и комментировать особенно нечего 😬 палец сам добавил в закладки.

Ответить
Развернуть ветку
red_mad_robot
Автор

Благодарим!

Ответить
Развернуть ветку
Kate Kras

спасибо, дельная статья!
но на "Основная ошибка, с которой мы сталкиваемся при разработке пользовательского интерфейса и опыта любого веб- или мобильного приложения, — мы прорабатываем основной сценарий, но забываем про краевые сценарии." ожидалось еще раздел про полноту, необходимость и достаточность требований на этапе проектирования.
возможно, это отдельная тема для целой статьи

Ответить
Развернуть ветку
red_mad_robot
Автор

Спасибо за комментарий! Подумаем над идеей)

Ответить
Развернуть ветку
Marina Ilina

Отличная исчерпывающая статья на тему краевых сценариев, но от заголовка ожидала более широкого взгляда на проблему. Возвраты задачи в дизайн на этапе разработки не всегда связаны с непродуманностью краевых сценариев, есть еще масса причин, часто дизайнеры отложив работу на какое-то время, начинают смотреть на нее новым взглядом, возникают улучшения, появляются изменения в макетах, и хорошо если о них предупреждают разработку:)
В статье упоминаются только кейсы из мира кровавого энтерпрайз и подход api-first, то есть проектирование интерфейса основано на заранее известном контракте между фронтом и бэком. Есть еще мир стартапов, в котором чаще встречается подход design-first, когда техническое решение выбирается исходя из требований UX. И там есть свои нюансы.

Ответить
Развернуть ветку
Женя Ткаченко

Статья просто топ !) как раз кое-что упустила из краевых сценариев, вовремя статья попалась !)))

Ответить
Развернуть ветку
Sergey Mayakovsky

Сижу, читаю пост, и тут прилетает, это что, слежка?)

Ответить
Развернуть ветку
4 комментария
Раскрывать всегда