Pull to refresh

Comments 32

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

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

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

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


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


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

UFO just landed and posted this here

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


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

UFO just landed and posted this here

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

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

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

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

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


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

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

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

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


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

т.е. пока сервер не ответил мы живём с временным случайно сгенреным ID а после того как сервер ответил уже с нормальным ID с сервера?
В целом ясно.

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

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

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

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

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

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

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

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

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

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