Эта запись о том, как увеличить скорость навигации и взаимодействия пользователя с интерфейсом, не прибегая к оптимизациям вычислений и рендеринга. Рекомендации касаются приложений, где сервер используется только для получения данных, а вся логика интерфейса находится в самом приложении. Эта запись о преимуществе клиентских приложений над приложениями с плохо разделённой логикой, представлением и данными.
Особенно ценными рекомендации могут оказаться для тех, кому приходиться вести разработку или проектировать интерфейс, когда данные от сервера приходят не слишком быстро, а обращаться к нему чересчур часто нельзя.
Правила организации высокоскоростного взаимодействия пользователя с приложением можно сформулировать следующим образом:
- Вычисления не должны блокировать взаимодействие с интерфейсом и его рендеринг — пользователь всегда должен иметь возможность указать на фокус своих интересов.
- Страница объекта, к которому обратился пользователь, должна отображается мгновенно, не дожидаясь загрузки данных, в которых нуждается объект.
- Запросы в сеть не должны уходить одной большой группой, не должны отправляться сразу; должны откладываться на небольшое время, складываться и приоритезироваться в случае необходимости.
Изложенная в этой заметке информация — это мой практический опыт проектирования и разработки интерфейса моего приложения для поиска и прослушивания музыки seesu.me/. Приложения, в котором гармонично комбинируются огромные пласты данных из разрозненных сервисов, таких как last.fm, вконтакте, ex.fm, hypem.com, soundcloud.com, discogs.com, youtube.com
Рекомендации, связанные с улучшением обратной связи без улучшений производительности, публиковались про работу приложения instagram. Но рекомендации не касались ни навигации, ни получения данных, а, скорее наоборот, — были связаны с отправкой.
speakerdeck.com/mikeyk/secrets-to-lightning-fast-mobile-design
Мне не встречались приложения, использующие подобные принципы. Однако, реализовав требования этих правил в сису на системном уровне, учитывая их при проектировании взаимодействия с новыми частями приложения, я могу с уверенностью сказать, что, придерживаясь этих правил, вы сможете кардинально улучшить впечатление пользователя от скорости взаимодействия со своим приложением.
Я пришел к этим правилам, в результате последовательного соблюдения принципа «мгновенной обратной связи», действуя в условиях технических ограничений, встающих на пути, и реализованных мною экспериментов.
Мгновенная обратная связь — это только один из нескольких базовых принципов, которых я придерживаюсь. Проектируя интерфейс своего приложения для прослушивания музыки, я руководствуюсь принципами и идеями, изложенными в книге Джефа Раскина «Интерфейс: новые направления в проектировании компьютерных систем». А также выводами и следствиями из его идей.
Джеф Ра́скин — специалист по компьютерным интерфейсам, автор статей по юзабилити и книги «The Humane Interface», сотрудник № 31 фирмы Apple Computer, наиболее известен как инициатор проекта Макинтош в конце 70-x.
Кратко основные используемые мной тезисы из книги я могу сформулировать так:
- Представление информации должно быть реализовано в виде масштабируемой структуры;
- Мгновенная обратная связь, выдача максимально возможной структурированной информации при минимуме введенных данных;
- Только контекстное требование дополнительного ввода данных от пользователя. Только в момент непосредственной необходимости дополнительных данных.
- Отказ от «интуитивности», «количества кликов», “количества нажатий” как мер эффективности интерфейса;
- Формирование новых привычек пользователя;
- Полный отказ от модальных окон.
Так, руководствуясь принципом мгновенной обратной связи из книги, опубликованной впервые в 2000 году, я запустил habrahabr.ru/post/88494/ мгновенный поиск за пол года до того как google запустил instant search. en.wikipedia.org/wiki/Google_Search#Instant_Search
Подробнее о каждом из правил необходимых для обеспечения быстрого взаимодействия пользователя с интерфейсом:
- Что бы не происходило в приложении, как бы оно не было занято вычислениями, пользователь всегда может указывать на то, что ему нужно. В приложении, написанном на джаваскрипте я использую setTimeout для разблокирования интерфейса (так же я планирую использовать setImmediate, и requestAnimationFrame — рендеринг не должен надолго блокировать возможность кликать и т.д.).
- Сразу, ещё до загрузки данных, наполняющих объект, отображается не просто страница объекта сама по себе, не пустой экран, но вся её структура. Отображаются её части, визуальные блоки, которые так или иначе зависят от данных, ещё не полученных из сети. Кроме этого отображаются и все блоки объектов, вложенных в этот объект. Когда приходят данные, отображаемые блоки наполняются. Это позволяет пользователю сразу анализировать структуру страницы и принимать решение о перемещении к другому объекту, не дожидаясь окончания загрузки.
- При перемещении от объекта к объекту пользователь четко даёт знать о фокусе своих интересов. В первую очередь должны быть выполнены запросы на получение данных для целевой страницы пользователя. Остальные запросы могут быть выполнены позже либо вообще отменены, например это такие как невыполненные запросы для страниц, которые покинул пользователь. Объекты могут быть вложены в другие объекты и иметь собственные запросы. Одни из запросов могут быть нужны для отображения данных в контексте пользовательского интереса, а другие — нет. Приоритеты таких запросов также следует изменять, причём в таком порядке, в котором данные используется на странице, и, соответственно, в том порядке, в котором объявлены представления вложенных объектов. (Т.е. страница, состоящая из множества элементов и вложенных объектов, будет пополнятся по мере поступления данных сверху вниз).
При переходе к странице артиста сразу же отображается вся структура страницы.
Без ожидания полной загрузки информации об артисте пользователь может сразу же перейти к лучшим композициям артиста. После указанного перехода, в первую очередь загрузится список лучших композиций, и только потом будет получена информация об артисте.
Чтобы полностью отобразить страницу артиста, соблюдая требование выдачи максимально возможной структурированной информации при минимуме введенных данных, в seesu выполняется 3 запроса в last.fm, 3 в hypem.com, 2 в discogs.com, 2 в soundcloud.com.
И чтобы перейти к любой из частей страницы артиста, нет необходимости дожидаться загрузки данных ни по одному из запросов.
Вы можете сами зайти на seesu.me/o#/catalog/Pixelord/_ и попробовать быстро переключать разные композиции для того, чтобы убедиться, что данные для последней выбранной композиции будут загружены скорейшим образом. И только потом будут загружены данные для следующей композиции и некоторые данные для предыдущей.
Так же (в качестве эксперимента) можно попробовать открыть страницу списка списков композиций last.fm пользователя http://seesu.me/o#/users/lfm:yodapunk/tracks, где элементы загружаются сверху вниз. Выберите самый последний элемент из загруженных и убедитесь, что он загружен, после чего можно мгновенно вернуться вернуться назад, чтобы обнаружить, что выбранный вами список загружен вне очереди.
Комбинация трех этих подходов и относительно фиксированное расположение, высота и ширина визуальных блоков позволяют осуществлять комфортное и крайне быстрое перемещение внутри приложения, формирующееся в привычку. Ускорение рендеринга, вычислений и уменьшение времени получения ответа от сервера сделает приложение молниеносным, а ненавязчивая анимация переходов между страницами сгладит впечатление от задержки при выполнении сетевых запросов (в Seesu я использую анимацию длительностью в 120 мс).
О том, как я пришёл к этим правилам
(можно не читать)
Когда я упомянул технические трудности, я имел ввиду как ограничения на сетевые запросы сервисов, которые я использую, так и ограничения и нагрузку браузеров.
Например, вКонтакте запрещал отсылать больше одного запроса в секунду.
Реализовав очередь с отправкой запросов (на поиск файлов для композиций) через каждую секунду, я обнаружил, что выполнение всей очереди затягивается на весьма длительное время. Очередь образуется достаточно быстро: стоить лишь кликнуть по нескольким разным композициям. Ожидание, пока начнётся воспроизведение последней выбранной композиции, становится неприятным, особенно, когда ты видишь, что файлы ищутся не для выбранной композиции, а для тех, от воспроизведения которых, ты отказался. Стало понятно, что файлы должны быть найдены в первую очередь для текущей выбранной композиции.
Отображать структуру страниц я стал после некоторых размышлений над принципом отображения максимума структурированной информации при минимальном вводе. На клиентской стороне у меня имеется шаблон — информация о визуальной структуре страницы, её скелет. Почему бы не отображать её? Мгновенное отображение шаблона и тех данных, которые я получил не для страницы, но которые могут быть использованы на ней, — это прямое следование одного из тех принципов, который я сформулировал для себя, прочитав книгу
— принципу мгновенной обратной связи, отображения максимума структурированной информации при минимуме введенных от пользователя данных.
У api сервиса last.fm нет ограничений на количество запросов, однако, при быстром перемещении от страницы к странице количество одновременно выполняемых запросов могло в ряде случаев более 6 (шести). Ни один браузер не открывает больше 6 соединений к одному домену. При большом количестве запросов становится заметна нагрузка на него. Я обратил внимание на то, что пользователь может передумать и переместиться на другую страницу до того, как будут получены данные по запросу. Это наблюдение делает очевидным тот факт, что мгновенная отправка запросов не сокращает ожидание получения пользователем нужной информации, а, наоборот, увеличивает. Поняв это, я принял решение разряжать и приотизировать все сетевые запросы.
Приоритезация запросов на первоначальном этапе была реализована исключительно для страниц со списком композиций. В дальнейшем, когда я стал гораздо активнее использовать last.fm api, подключая новые источники данных, я реализовал приоритезацию и разрядку запросов для всех страниц, для всех api. Сейчас при переходе от страницы к странице, при добавлении нового запроса в существующую очередь, приоритеты автоматически пересчитываются, меняются, учитывая текущую страницу и запросы, необходимые ей. Остальные запросы выполняются (не завершаются) в обратном порядке добавления.
Разрядка запросов может крупно помочь, когда нет возможности повлиять на серверную сторону, а так же в тех случаях, когда с серверной стороной нужно обращаться бережно.
Приходилось ли вам слышать?
— «БУДЕТ БОЛЬШАЯ НАГРУЗКА НА СЕРВЕР!»
С помощью отложенной отправки, разрядки запросов и мгновенной обратной связи в сентябре 2010 года мы с rossomachin сделали самую крутую форму проверки доменов shop.masterhost.ru/templates/default/domains/. Несмотря на технические ограничения и ограниченную реализацию наших пожеланий со стороны серверных разработчиков.
О будущем разработки интерфейсов
(можно не читать)
Если мы хотим, чтобы нас окружали современные интерфейсы, то мы должны обладать инструментами, способами описания интерфейсов, языками программирования, учитывающими хотя бы требования к интерфейсам, сформулированным 14 лет назад. Эффективность создания интерфейсов должна сильно увеличиться.
Кому-то до сих пор не очевидна польза от мгновенной обратной связи. Кого-то вдохновляет этот принцип и возможная продуктивность от взаимодействия с интерфейсами, соблюдающих его. Например с такими интерфейсами, которые предоставляют мгновенную интерпретацию введённых данных:
Вместе с этим по минимальному существованию приложений с мгновенной обратной связью можно сделать вывод, что людей приложивших руки к реализации подобных приложений немного. Найти этому объяснение несложно — реализация подобных принципов действительно трудозатраный процесс.
Последовательное и планомерное соблюдение принципа мгновенной обратной связи при реализации в сису требовало от меня дополнительного программирования, времени по проектированию дополнительных состояний интерфейса.
В моем случае все страницы приложения должны быть спроектированы с возможностью отображения их без загруженных данных; с учетом того, что страница должна наполняться, перерисовываться по мере поступления данных. Такое требование с точки зрения технической реализации должно было быть сделано без нагрузки на браузер — с помощью атомарных изменений DOM. Либо с помощью перерисовки огромных визуальных блоков, что вызывало бы нагрузку на браузер. Загруженный браузер лишает пользователя возможности быстрого взаимодействия. На реализацию частичной перерисовки отображения должно быть потрачено время сначала ручным, полуавтоматическим способом для каждой страницы. Позже это время сведётся к минимальному после того, как будет потрачено время на создание системы для автоматических перерисовок. Должна была быть реализована приоритезация запросов с учётом взаимосвязей, потому что запросов много и они образуют неуправляемые, нагружающие браузер очереди.
Помимо последовательного соблюдения этого принципа я последовательно реализую и другие принципы из книги Джефа Раскина. Например отсутствие модальных окон, представление данных в виде масштабируемой структуры. Принципы определяют не только как выглядит приложение, но и то как написан код приложения. Принципы, конечно, определяют сколько времени будет потрачено на разработку приложения.
Что бы организовать код, отвечающий сложным требованиям и не сойти сума, занимаясь в одиночку приложением с огромными пластами данных, я использую самописный фрейворк и шаблонизатор. Код описывает сложные взаимосвязи объектов, взаимосвязи их состояний, структуру страниц; отвечает требованиям отображения данных в масштабируемой структуре, приоритезации объектов, удобной шаблонизации, принципу разделения на MVC. Я уверен, что справлюсь с построением любого нового интерфейса, отвечающего всем перечисленным требования, используя в связке собственные инструменты гораздо эффективней, чем используя другие существующие на рынке инструменты. Эффективность моих инструментов можно улучшить, но даже после улучшений ничего из этого не сможет стать инструментом делающим доступной возможность построение современных интерфейсов для широких слоев разработчиков. Также как и другие библиотеки не являются таким инструментом. При этом для меня очевидно, что существование таких инструментов возможно.