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

Що відбувається, якщо раптом на клієнті пропадає інтернет? Можливо, на частку секунди, а може бути, на більш відчутний період? Всі ми як користувачі стикаємося з нестабільним сигналом, плаваючим якістю зв'язку. Іноді це неважливо, адже хочеться подивитися якесь веселе відео, іноді від цього може залежати дуже багато чого – уявіть, що вам терміново треба купити квиток на поїзд або оплатити той самий інтернет.

Ті сфери, де дуже важливий кінцевий користувач – наприклад, ЗМІ, кажуть, що вже 13% користувачів йдуть, якщо ваш сайт відкривається більше чотирьох секунд, не розбираючись в причинах. А тепер давайте уявимо такого користувача, який ще пробує відправити коментар, і він постійно «відвалюється» з-за проблем зі зв'язком?

Відсоток відходів і відмов буде явно більше. Як цього уникнути? Що можна зробити в ситуації, коли дані повинні бути гарантовано відправлені як від клієнта, так і з боку сервера?

На це та інші запитання відповідає Андрій Ситник – автор 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. Крім того, можна буде відразу подивитися доповіді, присвячені й іншим обговорюваним технологій:
Джерело: Хабрахабр

0 коментарів

Тільки зареєстровані та авторизовані користувачі можуть залишати коментарі.