Не так давно на сайте Smashing Magazine появилась статья Дениса Мишунова, с переводом котрой можно ознакомиться на Хабре.

Вслед за этой статьей вышла еще одна – «Optimistic UIs in under 1000 words» за авторством Игоря Мандригина, в которой он затрагивает ту же тему, дополняя ее и иллюстрируя большим количеством примеров. Предлагаем вашему вниманию перевод.



Кратко про оптимистичный UI. Оптимистичные интерфейсы в картинках.

Давайте сегодня поговорим об оптимистичном UI дизайне.

В каком смысле оптимистичном?

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


Не оптимистичный (слева) против оптимистичного (спрва)

Итак, оптимистичный UI дизайн показывает конечное состояние до того как приложение в действительности заканчивает (или даже начинает) операцию.

То есть это просто фокус. Зачем тогда это нужно?

Идея, которая скрывается за замысловатым названием, очень проста. Тем не менее, это может оказать огромное влияние на впечатление ваших пользователей (или «удовлетворить клиента», если вы Apple). Во-первых, это создает ощущение, что приложение работает быстрее, как бы «ускоряя» ваше приложение. Пользователь может сделать что-то еще, пока приложение загружает потешную фотку с котиком или отправляет ироничный комментарий в дискуссию. Во-вторых, это упрощает взаимодействие с интерфейсом, убирая лишние состояния и отвлекающие факторы. Приложение выглядит более простым и доступным. Да и UI дизайнерам придется меньше экранов доводить до состояния Pixel-Perfect.

Примеры из жизни

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


Незамедлительное обновление интерфейса в Messages на Mac.

Инстаграм применяет подобное же решение для добавления комментариев:


Комментарии в Instagram. Обратите внимание на индикатор прогресса справа.

Давайте рассмотрим пример другого плана: приложение Audible – проигрыватель для аудиокниг на iOS. Как только небольшой фрагмент записи подгрузится, пользователь сразу может начать прослушивание, пока остальная часть трека догружается.


Как только часть книги загрузится, появляется надпись «Ready to play». Оптимизм в чистом виде.

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


Optimistic UIs are key to Trello’s fluency
Оптимистичные интерфейсы – ключевая фишка удобства Trello


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

Прогресс

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

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


Отображение прогресса рядом с сообщением

Другой способ — добавить маленькую иконку или ярлычок, демонстрирующие статус отправки сообщения рядом с ним.



Иконки статуса (Facebook Messenger)

Сообщения на iOS вдобавок выдают индикатор состояния поверх окна. Особенно он бросается в глаза, когда загружаешь потешную фотку с котиком (одну или много).


Индикация прогресса в приложении Messages в iOS

Сообщения об ошибке
А если что-то пошло не так? При проектировании сообщения об ошибке следует обратить внимание на следующее:

1. Заметность. Оповещение должно быть хорошо видно, чтобы пользователь никак не мог его пропустить (особенно в тех случаях, когда загружает данные).

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

Сообщения об ошибке — самая сложная задача для дизайнера оптимистичных интерфейсов.

Самое простое решение — это, конечно, Good Old bLocking Error Message (GOLEM) — старое доброе блокирующие окошко.


GOLEM в действии!

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

Другое распространенное решение —показать кнопку или иконку рядом с сообщением, которое не удалось отправить.


WhatsApp, не надо так!

Когда пользователь нажимает на нее, показываем диалог GOLEM или пытаемся повторить действие без диалога.


Диалог GOLEM вызывается нажатием на индикатор ошибки (приложение Messages в iOS)

Здесь, напротив, все в порядке с причинно-следственными связями (пункт 2), но, к сожалению, не достаточно заметно. Если юзер уже переключился на другой экран или прокрутил переписку, оставив сообщение за пределами экрана, оповещения он не увидит.

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


Messages намекает нам, что что-то пошло не так

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

Заключение

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

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

Так что принимайте все эти соображения во внимание и пользуйтесь данным решением с умом!
Поделиться с друзьями
-->

Комментарии (32)


  1. agent10
    15.12.2016 12:03

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


    1. EverydayTools
      15.12.2016 13:25
      +1

      Есть простор для продолжения темы!


  1. gsaw
    15.12.2016 13:06
    +1

    По мойму мужик на иллюстрации плачет.


    1. EverydayTools
      15.12.2016 13:23
      +1

      Это оптимистичный Гарольд, скрывающий боль, сдерживает слезы радости!


      1. gsaw
        15.12.2016 13:30

        Блин, совсем мимо прошло.


  1. yury-dymov
    15.12.2016 13:14
    +1

    Optimistic UI создает куда больше проблем, чем приносит пользы. Я сейчас как раз готовлю доклад на эту тему, где буду активно пинать эту концепцию. На самом деле, эта идея новая только для веба, а в мобайле ей больше 10 лет


    1. EverydayTools
      15.12.2016 13:24

      Спасибо за комментарий. Можно попросить Вас потом поделиться материалом? Или ссылкой, если будете делать публикацию?


      1. yury-dymov
        15.12.2016 13:53
        +2

        Я буду весной выступать, материал пока в процессе разработки.


        Основные проблемы:
        1) вы не можете использовать Optimistic UI всюду. Очевидно, что у вас будут критичные процессы, где нельзя обманывать пользователя. В итоге это и для вас накладные расходы, и для пользователя: вам надо реализовывать два механизма работы с API/backend и пользователю тоже может быть неочевидно, что случилось "на самом деле", а что нет.
        2) При выходе из оффлайна или при обработке очередной порции отложенных действий, у вас может упасть промежуточное действие, и нет решения в общем случае, как это правильно разрулить: rollback всех действий? игнор и выполнение последующих? А если они связаны? Как UI адекватно обновить, если 7 действий случились, а 3 упали? Причем разруливать надо и на сервере, и на клиенте. Самое печальное, что каждый подобный кейс требует обдумывания, а "думать" — это штука, которая плохо поддерживается, масштабируется и реюзается.


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


        1. Aingis
          15.12.2016 16:38

          По идее свежеобъявленный logux сможет решать проблемы такого рода.


          1. yury-dymov
            15.12.2016 17:08

            Лол, его я буду пинать больше всех, потому что тот уровень сложности, который он добавит в проекты со 100+ пользователями я даже измерить не могу. Мы с автором немного пообщались недавно и надеюсь, что у нас будет дружественный баттл через некоторое время. Он парень очень умный, поэтому хочу пожелать ему успехов, и надеюсь, что моя критика лишь поможет ему сделать крутое решение.


            Если чуть более предметно, то он не решает ни одной из этих проблем: вам не только нужно на сервере реализовывать conflict resolution, но еще и логи где-то хранить, причем непонятно как долго. Хуже того, вы не можете доверять логам, так как by design timestamp "не должен расходиться больше секунды", но если при первом подключении у нас случился delay в 3 секунды, то timestamps уже разошлись, не говоря о том, что никто не мешает клиенту подделать timestamp. Там есть еще пачка проблем, но я о них, пожалуй, умолчу, а то на доклад ничего не останется


            1. Aingis
              15.12.2016 19:40

              Думаю, тут только практика рассудит (и организация процесса). Имхо, главное преимущество оптимистичного интерфейса — его неинтрузивность. Он не мешает пользователю в выполнении задач как беспощадные и довольно бессмысленные для пользователя модальные окна «Стой! Произошла ошибка!»


              1. vintage
                15.12.2016 20:19

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


            1. eBuster
              15.12.2016 21:26

              В докладе проблема недоверия в пользовательскому timestamp рассматривалась, и как я понял из слайдов — для этого предусмотрено решение есть.


              1. yury-dymov
                15.12.2016 22:08

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


      1. vlaabra
        16.12.2016 01:15

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


    1. agent10
      15.12.2016 13:27

      А можете кратко пару-тройку проблем?



  1. stalkerg
    15.12.2016 14:59

    Это похоже на асинхронный UI. Собственно и проблемы от этого уже описаны выше.
    По факту получается так — по умолчанию всё делает синхронным и только там где это точно никому не навредит делаем оптимистично/асинхронно.


    ЗЫ к слову как однозначно определяется к примеру сообщение которое ещё не побывало на сервере? Ей на клиенте придумываем ID? Ведь когда от сервера придёт ответ надо точно понять о каком таске этот ответ.


    1. Revertis
      15.12.2016 15:16

      У запроса есть айди, и у ответа будет.


      1. stalkerg
        15.12.2016 15:25

        откуда он взялся? Как его с генерировали? Как избежать коллизий?


        1. yury-dymov
          15.12.2016 15:34

          В мобильном мире это делается так:


          1) на клиенте генерится очень большой временный id, который хранится локально, разумеется, мы умеем отличать временные и полноценные данные
          2) При синхронизации сервер обрабатывает запрос и возвращает ответ с тем id, который присвоен в backend.
          3) Конфликтов, как правило, избежать нельзя, поэтому бэкенд согласно реализованной бизнес-логике разруливает такие ситуации, как мы хотим.


          1. roversochi
            28.03.2017 09:17

            Оба варианта не очень надежные. Вариант с лазером самый точный, если их поставить хотя бы два.
            С энкодерами в случае прокручивания колеса все показания датчиков можно смело удалять :)
            Можно в комнаты повесить камеры, и анализируя изображение, определять текущее положение. Ну опять же, esp тут необходим. Лежит у меня, ждет, пока я с механикой разберусь :)
            Еще можно на полу наклеить всяких меток — вместе с энкодерами это неплохой вариант.


            1. yury-dymov
              16.12.2016 15:28

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


        1. Revertis
          16.12.2016 16:22

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


          1. yury-dymov
            16.12.2016 17:01
            +1

            А если модифицируют один и тот же объект, при этом из-за оффлайна/медленного интернета более старый запрос приходит вторым?


  1. ilkz
    15.12.2016 17:40
    +1

    Яблоко!


  1. KodyWiremane
    16.12.2016 05:40
    +2

    После прочтения перевода, упомянутого в первом абзаце, сложилось впечатление, что чуть ли не best practice оптимистичного интерфейса является отсутствие индикации незавершённого запроса. Здесь же ОИ выглядит как грамотно сдизайненный асинхронный интерфейс (как замечено в комментариях), когда крутилка не блокирует весь UI, а элегантно индицирует выполнение действия, которому посвящена.

    Мне кажется, даже если организовано локальное хранение необработанных сервером запросов (чтобы переотправить их позже, если юзер уходит со страницы или рвётся связь), какая-то индикация незавершённости действия должна присутствовать. Многие люди не слишком задумываются о механизмах работы вычислительной техники, вот, например, статья на Geektimes. Увидев элемент UI сразу в финальном состоянии без какой-либо переходной индикации, он посчитают данное изменение Вселенной совершённым, и будут потом озадачены исчезнувшими лайками, комментариями и всем чем угодно, что дизайнеры сочтут второстепенным. Или будут уверены, что отправили срочное сообщение, в то время как оно незаметно зависнет в очереди на отправку ввиду отсутствия связи.


    1. Petrichuk
      17.12.2016 09:04

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


  1. perfect_genius
    17.12.2016 10:35

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


  1. ElectroGuard
    19.12.2016 06:38
    +1

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


  1. geekmetwice
    20.12.2016 21:40
    +1

    Как осторожный человек, я выступил бы против этих «оптимистичных обманщиков». Если я что-то делаю с компьютером, он обязан отвечать на мои действия и чётко рапортовать об их результате. Сообщения — они только для прогеров выглядят ерундовым набором байт, а в реале от них может зависеть жизнь. И разумеется, я не хочу обнаружить через час, что сообщение «У меня пожар» не отослалось, потому что вайфай отвалился!

    Как вариант конкретно с мессенджером, что мешает отображать неотосланные сообщения другим цветом?? Пока оно оранжевое (что хорошо показывает накал ситуации), оно ещё в очереди. Отослалось — поменялось на зелёный. В этом случае я никогда не пропущу проблему доставки.


  1. pronvit
    21.12.2016 05:50

    Столкнулся с подобной проблемой при разработке Dwarf Fortress Remote (iOS клиент для Dwarf Fortress). Например, пользователь помечает предметы для торговли или делает множество каких-то других однотипных операций на экране. Логично в этом случае тут же изменять состояние интерфейса — не хочется же ждать после каждого из 20 нажатий. Но как уведомить пользователя, если какая-то из операций не удалась? А если он уже ушел с этого экрана? Ситуация осложняется тем, что состояние игры на сервере и на клиенте в некоторых случаях обязано быть быть синхронизировано (например, на каком экране находится пользователь).

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

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