КейсыРастИИшка
Разработка

Офлайн-режим приложения: как сохранить работу и согласовать изменения

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

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

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

Сначала договориться, что сотрудник может сделать без сервера

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

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

В руководстве Android по offline-first архитектуре описывается сочетание локального и сетевого источников данных. Практический вывод для постановщика задачи: офлайн затрагивает слой данных и бизнес-логику, а не только иконку отсутствия Wi-Fi. Экран не может надёжно обещать то, для чего не предусмотрено сохранение и последующее согласование.

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

Ранее загруженный справочник должен показывать свой возраст

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

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

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

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

Запись на устройстве, ожидание передачи и принятие сервером — самостоятельные состояния, которые нельзя скрыть одной галочкой.
Запись на устройстве, ожидание передачи и принятие сервером — самостоятельные состояния, которые нельзя скрыть одной галочкой.

Первый успех — запись на устройстве, второй — принятие сервером

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

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

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

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

В очереди хранится понятное действие, а не надежда на повтор

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

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

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

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

Значок сети не подтверждает, что сервер принял запись

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

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

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

Фоновая отправка также не обязана срабатывать мгновенно. Для веба Background Synchronization API описывает отложенную работу через service worker, но имеет ограничения доступности. Нельзя строить единственный путь передачи на неподдерживаемой возможности. Нужны проверенные запасные сценарии: синхронизация при открытии, понятная ручная команда и видимый статус очереди.

Настоящий конфликт начинается, когда работают двое

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

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

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

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

Позднее поступление не делает изменение более правильным. Конфликт разрешается по правилам конкретных данных.
Позднее поступление не делает изменение более правильным. Конфликт разрешается по правилам конкретных данных.

Сначала акт, потом фотография — или наоборот, но по договорённости

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

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

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

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

Ожидающая очередь не должна пересесть в чужой аккаунт

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

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

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

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

Часы телефона не должны единолично назначать правду

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

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

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

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

Время работы, локальной записи и принятия сервером различаются; часы телефона не являются единственным арбитром.
Время работы, локальной записи и принятия сервером различаются; часы телефона не являются единственным арбитром.

Цена офлайн-режима — не только одна локальная база

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

Возьмём учебный расчёт. Двадцать сотрудников выполняют по восемь выездов в месяц. На трети из 160 выездов возникает проблема связи; для простоты примем 54 случая. Если каждый требует десяти минут повторного ввода или восстановления записи, это девять часов работы. При условной внутренней стоимости часа 1 500 рублей получаем 13 500 рублей прямых трудозатрат в месяц. Это иллюстрация метода, не измерение клиента.

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

Уровень решенияЧто получает сотрудникКакая сложность остаётся
Локальный черновикНе теряет введённую формуПодтверждение и передача требуют связи
Чтение плюс очередь действийПродолжает согласованный набор работПовторы, права и ошибки передачи
Несколько редакторов офлайнРаботает с общими объектамиВерсии, конфликты и правила объединения

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

Авиарежим на пять секунд не заменяет полевой тест

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

В тесте конфликтов два пользователя начинают с одной версии и меняют одинаковое поле. Ожидаемое решение задают заранее. Затем проверяют независимые поля, отмену, удалённый объект и отозванный доступ. Для каждого результата должны существовать понятный статус, журнал и доступное действие ответственного. Фраза «конфликт» без возможности его разобрать просто переносит работу в поддержку.

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

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

В паспорте процесса должны быть статусы, пределы и владелец разбора

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

  1. Назвать критические операции без связи и исключить недопустимые обещания.
  2. Определить срок допустимого устаревания локальных справочников.
  3. Разделить сохранение на устройстве и подтверждение общей системой.
  4. Задать идентификаторы операций, зависимости и поведение повторов.
  5. Описать конфликты для конкретных полей и назначить владельца решения.
  6. Проверить выход из аккаунта, отзыв доступа и потерю устройства.
  7. Испытать очередь после закрытия, перезапуска и обновления приложения.
  8. Измерить потерянную работу, время восстановления и обращения в поддержку.

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

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

Частые вопросы

Что должно работать в офлайн-режиме приложения?

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

Чем локальное сохранение отличается от синхронизации?

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

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

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

Что делать, если два сотрудника изменили одну запись офлайн?

Сервер выявляет конфликт по версиям и применяет заранее заданное правило: объединение независимых данных, отказ или разбор человеком. Решение зависит от конкретного поля и последствий потери.

Нужна ли полная автономность каждому приложению?

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

Начать приложение с одной операции

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

Посмотреть форматы приложений ↗

Разобрать свой сценарий ↗

Сравниваете несколько направлений? Соберите бриф по задаче.