Logux: Connection lost, data synchronized – интервью с Андреем Ситником (Злые Марсиане)

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

Те сферы, где очень важен конечный пользователь — например, СМИ, говорят, что уже 13% пользователей уходят, если ваш сайт открывается больше четырёх секунд, не разбираясь в причинах. А теперь давайте представим такого пользователя, который еще пробует отправить комментарий, и он постоянно «отваливается» из-за проблем со связью?

Процент уходов и отказов будет заведомо больше. Как этого избежать? Что можно сделать в ситуации, когда данные должны быть гарантированно отправлены как от клиента, так и со стороны сервера?

bf3a94cf715e478d8d3393abcb405283.jpg На этот и другие вопросы отвечает Андрей Ситник — автор PostCSS и Автопрефиксера, ведущий фронтендер в «Злых Марсианах».

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

— OSI тут не совсем в тему. Logux заменяет REST и AJAX. То есть это чисто прикладной уровень. Logux решает следующие проблемы:

  1. Сейчас требуется много кода для простых запросов.
  2. Живое обновление данных с сервера писать на порядок сложнее.
  3. Хорошую поддержку оффлайн вообще ад написать. Но оффлайн нужен всегда, так как у нас всегда есть »500 мс оффлайн» — эти постоянные крутилки на кнопках.

Для этого Logux как бы создаёт особый виртуальный канал событий между клиентом и сервером.

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

Разбор полетов


1. На клиенте это будет библиотека с API один-в-один как у Redux (к Реакт не привязана, есть и более низкоуровневый API). Ты точно так же создаёшь action. Но у некоторых action можешь выставить ключ sync: true — тогда Logux доставит их сам на сервер. Эта библиотека держит веб-сокет, посылает пинг, проверяя, что связь есть.

 — Так, а чем хорошо то, что эта библиотека не привязана к Реакту?

Не все разрабатывают на Реакте (и это очень хорошо для разнообразия среды). Кто-то может использовать Vue.js, Angular. Или просто иметь JS-приложение, где нет HTML, так что Реакт будет не так нужен. Идём дальше:

2. Дополнительная библиотека, которая при потере связи покажет спец. бейджик «Нет связи» вверху страницы и изменит фавикон. Если в канале на отправку окажутся события, а связи не будет — она тоже скажет пользователю, что не все данные сохранились.

 — Зачем пользователю это знать? Для какого формата взаимодействия это может быть критически важным?

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

Следующий шаг.

3. Когда связь появится, Logux-клиент и сервер отправят друг другу те события, которые добавились за время отсутствия связи.

— Понятно, логично, сколько действий может быть в очереди?

— Обычно событий 10–20. Но у нас нет жёстких ограничений — сколько поместится в памяти клиента и сервера.

— Порядок выполнения этих событий?

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

— Не будет ли так, что какие-то события уже не надо выполнять? Взаимная проверка зависимости действий?

— Клиент может чистить лог от уже ненужных событий. Это уже определяется бизнес-логикой.

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

— Опять возвращаемся к вопросу ёмкости и важности, и что произойдёт, если пользователь принудительно закроет браузер?

— Ничего страшного. Как только пользователь снова вернётся на сайт — данные сами отправятся.

Теперь все оставшиеся шаги:

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

6. Фреймворк для сервера пока на node.js. Потом сделаем для Elixir и Go. Но можно использовать и Ruby, Python и PHP — просто поставить node.js сервер как прокси, чтобы держать сокет. А уже этот прокси-сервер будет посылать старый REST-запрос в ruby-сервер.

7. Поскольку у нас есть этот лог событий и точное время, поверх него можно сделать CRDT как в Swarm.js — и автоматически разрешать конфликты во многих простых случаях.

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

Logux и альтернативы


— Спасибо, а чем Logux тогда лучше уже существующих решений?

— Есть Relay/GraphQL — они сокращают количество кода при запросе данных. Но изменение самих данных тут тоже реализовано не очень просто. Живое обновление решено плохо. Оффлайн тоже не проработан.

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

Есть ещё CRDT-библиотеки — например, Swarm.js. Logux копирует много идей у Swarm.js. Но Swarm.js сложно подружить с Реактом и Редаксом. Также сложно передавать в нём не-CRDT операции.

— В чём сильные и слабые стороны?

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

Главная слабая сторона — надо запускать дополнительный сервер. Но это есть у всех таких решений. Плюс этот сервер можно сделать прокси-сервером и всю логику продолжать хранить в PHP или Ruby on Rails.

— Откуда вообще появилась потребность в этом выделенном решении?

— На Амплифере нужно было показывать живую статистику публикаций и обновлять страницу с ошибками сразу же при появлении проблемы. И мы поняли, что хорошего решения не нашлось. Попробовали внедрить Swarm.js, но легко развернуть его не получилось. Так что я начал думать, как подружить Swarm.js и Редакс. В Питере в это время как раз был Дэн Абрамов, и в разговоре с ним родилась идея отдельной библиотеки.

— Имеет ли это шансы на то, чтобы стать индустриальным стандартом?

— Я стараюсь сделать Logux, как универсальное решение для всех веб-приложений. Но, мне кажется, в 2017 мы увидим много ещё попыток переделать AJAX/REST — сейчас это главная проблема веб-разработки, на мой взгляд. Кто победит в этой борьбе, узнаем только в 2018.

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


— Есть ли 1–2 интересных практических кейса?

— Да, даже TODO MVC — вам же хочется продолжить работать со списком задач даже, если связи нет. Или если вы добавили задание на компьютере, то хотите, чтобы оно появилось тут же и на телефоне, без перезагрузки страниц.

Или комментарии — живое обновление, как в Фейсбуке или ВК, полезно для вовлечения людей.

Есть ещё одно преимущество Logux для любого сайта — это «оптимистичный интерфейс» (о нём как раз рассказывал другой спикер HolyJS). Сейчас при каждом действии мы показываем пользователю «крутилку». Каждое сохранение блокирует интерфейс и нарушает поток пользователя. С помощью Logux на порядок проще делать оптимистичный интерфейс, где сохранение будет происходить в фоне, отвлекая пользователя, только если ошибка действительно произошла. Например, так работает Google Inbox. Любое веб-приложение выиграет от оптимистичного интерфейса, так как пользователи всегда любят быстрые интерфейсы.

— Большое спасибо за интервью, и до встречи на конференции.


Конечно, в интервью удалось обсудить только общий взгляд на библиотеку и ее философию, на HolyJS Андрей выступит с подробным часовым докладом о разработке и работе с Logux. Кроме того, можно будет сразу посмотреть доклады, посвященные и другим обсуждаемым технологиям:
  • Лебедь рак и щука: как технологии тянут фронтенд на дно
  • A Little Closer to Frontend Bliss with Elm

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

© Habrahabr.ru