Автор Денис Соколов

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

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

Текущие и устаревшие данные на экране

Причина моих эмоциональных американских горок была проста: на мгновение я потерял соединение Wi-Fi, и потребовалось некоторое время, прежде чем мой HTTP-запрос вернулся. Предположительно авторы не добавили индикатор загрузки, потому что это была незначительная функция, не стоящая усилий.

Точно так же, если бы кто-то другой отреагировал, пока у меня была открыта страница, я не увидел бы обновленного количества реакций, пока не обновил страницу. Предположительно потому, что добавление обновлений в реальном времени для этого не стоило усилий.

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

Если мы продолжим нашу проверку, мы обнаружим, что для каждой части информации на экране авторы решили, достаточно ли она ценна, чтобы добавлять обновления в реальном времени.

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

Архитектура

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

Каждая функция отвечает за выборку собственных данных: ей необходимо изменить форму данных, сохранить данные в локальном (Redux) хранилище, а затем распространить изменения данных обратно на сервер.

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

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

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

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

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

Инструменты

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

Конечно, уже есть инструменты более зрелые, чем это. Чтобы найти их, нужно искать брендинг в первую очередь офлайн. Это побочный эффект этой архитектуры, который привлекает наибольшее внимание. Но чтобы воспользоваться преимуществами дизайна, не нужно беспокоиться об офлайн-режиме. Самый крупный из таких инструментов - PouchDB. Он обеспечивает большую гибкость за счет некоторого изучения CouchDB. RxDB пытается настроить PouchDB с другим API. Meteor приносит с собой целый фреймворк, а Relay - целый синтаксис. Есть более мелкие, более сфокусированные инструменты, хотя и с менее активной поддержкой: Swarm, synceddb, scuttlebot и, пожалуй, самый полезный на данный момент, ShareDB.

Общие проблемы

Выбор данных для синхронизации

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

Конфликты

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

Сохранение нестандартных подходов

Более популярные архитектуры очень удобны, когда нужно создать сотню идентичных веб-сайтов, а затем поддерживать их. Но если это приоритет, я предлагаю Ruby on Rails или Wordpress. Тем не менее, синхронизация локальных данных с удаленными данными является устаревшей разработкой и не может быть названа «индивидуальной».

Back-end технология

Ни один из упомянутых инструментов не будет хорошо работать с обычным REST API. Ожидайте приложить некоторые усилия для обеспечения поддержки этих инструментов на сервере. PouchDB полагается на протокол репликации CouchDB. Meteor и ShareDB работают с MongoDB. Swarm строит свою собственную базу данных на основе простого механизма хранения.

Первоначально опубликовано на сайте bits.citrusbyte.com 31 августа 2017 г.