Разработка веб-приложений по принципу «Автономность прежде всего»

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

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

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

Такая зависимость от сети вызвана пренебрежением прописной истины: отсутствие подключения к сети - это суровая реальность. В какой-то момент, если вы передвигаетесь в пространстве, подключение к сети будет обязательно разорвано. И в этом нет ничего страшного. Существуют пути решения этой проблемы.

Проведём учёт проблем

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

Эта проблема была решена, отчасти, благодаря усовершенствованию клиентов, которое позволяет большинству алгоритмов приложения выполняться в напрямую браузере, как например, в Google Docs. Однако, для обеспечения качественного пользовательского опыта в режиме оффлайн, так же необходима возможность сохранения данных в клиенте и их синхронизации с массивом данных на сервере. К счастью, встроенные в браузер базы данных развиваются, и для этого уже существует большое количество решений вроде Derby.js, Lawnchair, Hoodie, Firebase, remoteStorage.io, Sencha Touch и других, так что поиск решений для технических аспектов становится более простым.

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

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

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

Как видите, с электронной почтой дела обстоят довольно просто. Она не поддаётся редактированию, легко может быть упорядочена в виде списка, состоит преимущественно из текста, исключает возможность конфликтов, и кроме того, принцип хранения локальных копий писем хорошо знаком всем пользователям. Однако, перспективы гораздо более широкие. Как организовать эти сценарии, к примеру, в приложении для совместного рисования? Что если мы имеем дело не с неизменными документами вроде электронных писем, а с маркерами карты с редактируемыми параметрами, MIDI-треками, задачами и действиями? Браузер - это наиболее оптимальная рабочая среда для нового приложения. И если учитывать Закон Этвуда, который гласит, что любое приложение, которое может быть написано на JavaScript, в конце концов, будет написано на JavaScript, то какие ещё немыслимые действия мы будем выполнять в браузере через несколько лет? Стоит ли и дальше считать оффлайн-режим пограничным случаем, и ограничивать реакцию на него нестабильными компонентами, раздражающими пустыми страницами и сообщениями об ошибках с паническим оттенком?

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

Жизненный цикл подключения к сети

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

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

Давайте рассмотрим примеры из реальной жизни.

Сценарии при возникновении проблем с подключением

Потеря локальных данных

Отключение сети во время использования Google Docs в браузере, отличном от Chrome, может привести к обескураживающему результату: редактирование документа становится невозможным. И хотя вы всё ещё можете читать текст документа, копировать его части также нельзя. С текстом или таблицей нельзя производить никаких действий, даже скопировать их в другую программу, чтобы продолжить работу в ней. И в то же время, в сравнении с предыдущими версиями, нынешняя значительно улучшена, так как раньше огромное оповещение об отключении от сети перекрывало документ так, что его нельзя было даже просмотреть.

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

Восприятие отключения от сети в качестве ошибки

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

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

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

Разрешение конфликтов между разными версиями данных

Если ваше приложение предлагает возможность совместного редактирования, или какую-либо другую форму совместного использования на нескольких устройствах, в определённый момент вполне вероятно создание конфликтующих версий объектов. Эту ситуацию невозможно предотвратить, но, существует довольно простой способ разрешения конфликта, который был бы удобен даже для тех, кто и понятия не имеет о конфликте синхронизации.

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

С другой стороны Draft, предлагает простое и изящное решение конфликтов при совместной работе. В нём обе версии и различия между ними выводятся в три отдельные колонки, для каждого различия предложена кнопка «принять» и «сбросить». Интуитивное и визуально привлекательное решение конфликтов между версиями без сомнений возможно, по крайней мере для текста.

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

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

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

Упреждение потребностей пользователя

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

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

Обновление хронологических данных

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

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

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

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

Подготовка к многообразию типов данных

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

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

Анонимные борцы с проблемами работы вне сети

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

Нам нет нужды сохранять анонимность. Мы можем взять на вооружение опубликованный 13 лет назад призыв Джона Оллсоппа (John Allsopp) к восприятию сети как непостоянной среды с множеством неизвестных и «признанию склонности вещей к метаморфозам». Сегодня мы понимаем, что ситуация выходит за рамки размеров экранов и соотношения их сторон, поддержки тех или иных свойств и подходов к их отображению, она затрагивает, в том числе, и наше подключение к сети.

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

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

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