Connect with us

Разработка

Я заставил мое приложение работать в офлайне — архитектурный сдвиг

Заставив своё приложение работать офлайн, я понял его истинную сущность.

Опубликовано

/

     
     

У каждого разработчика иногда ночью возникают безумные мысли. У меня она была простой:

«Что, если я просто отключу интернет и посмотрю, как поведёт себя приложение?»

И я так и сделал. Я потянулся за стол, выдернул Ethernet-кабель из роутера и понаблюдал, как мигает маленький индикатор Wi-Fi, как будто всё в порядке.

Но моё приложение знало правду.

Экран входа мгновенно заблокировал меня.

В ленте новостей не было ничего, кроме бесконечного спиннера.

Даже страница настроек не работала — как будто для включения тёмного режима нужен интернет.

Вот тут-то меня и осенило.

Моё приложение на самом деле не было приложением. Оно было просто марионеткой, которой управлял интернет, дергая за все ниточки.

А когда я отключил ниточки, марионетка рухнула.

И я принял решение:

Я переделаю своё приложение так, чтобы оно работало только в offline режиме.

Никаких оправданий. Никаких сообщений «попробуйте ещё раз позже». Только локальная архитектура.

И этот выбор изменил всё в моём подходе к разработке приложений.

Когда интернет исчез

Вот что сломалось первым:

  • Вход в систему: без сервера я не мог пройти даже приветственный экран
  • Вызовы API: каждый список, информация и действие зависели от облака
  • Навигация: некоторые экраны работали только при отправке данных API
  • Кэширование: мой так называемый «кэш» представлял собой просто остаточный JSON, а не настоящее хранилище
  • Обработка ошибок: вместо дружелюбного сообщения «Вы офлайн» я получал пугающие сообщения об ошибках

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

Поэтому я принял смелое решение. Я заставлю это приложение работать только в офлайн-режиме.

И вот тут-то и началось настоящее приключение.

Большой сдвиг в архитектуре

Мне пришлось всё переосмыслить. Вот как изменилось моё мышление.

1. От API-First к Local-First

До:

  • Каждый экран ждал ответа API
  • Сервер был «истиной»
  • Локальное хранилище было всего лишь коротким кэшем

После:

  • Локальная база данных стала «истиной»
  • Каждый фрагмент данных сначала находится на устройстве
  • Сервер используется только для синхронизации

Или, проще говоря, моё приложение перестало зависеть от облака. Оно стало работать самостоятельно.

2. Локальная база данных становится главной

Я годами игнорировал базы данных. Теперь они стали моими лучшими друзьями.

  • iOS: Я использовал Core Data. Немного сложно настроить, но очень мощно.
  • Flutter: Я попробовал Hive для простого хранения и Drift, когда мне нужен был SQL.

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

3. Слой синхронизации: новое сердце

Это был самый большой сдвиг в мышлении.

Старый способ:

UI -> Call API -> Show Results

Новый способ:

UI -> Save to Local DB -> Queue for Sync -> Push to Server (when online)

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

4. Разрешение конфликтов: сложная часть

Этот этап заставил меня потерять сон.

  • Что, если пользователь редактирует что-то офлайн… а на сервере уже есть новое обновление?
  • Чья версия правильная?

Я пробовал разные стратегии:

  • Последняя запись выигрывает: просто, но опасно — пользовательские правки могут исчезнуть
  • Временные метки и слияние: лучше, но запутанно
  • CRDT (замысловатые алгоритмы): слишком сложно для моего случая

В итоге я выбрал сочетание:

  • Для текста: выигрывает последнее редактирование
  • Для списков: слияние элементов
  • Для счётчиков: добавлять значения

Не идеально. Но гораздо лучше, чем молчаливая потеря данных.

5. UX тоже нужно изменить

Офлайн-приложения ощущаются по-другому. Мне пришлось переработать интерфейс.

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

Два моих эксперимента: iOS и Flutter

Поскольку я делал приложение и на Swift, и на Flutter, вот как я решил эту проблему.

iOS (Swift + Core Data + Фоновая синхронизация)

// Save note offline first
func addNoteOffline(title: String, content: String) {
    let note = NoteEntity(context: context)
    note.title = title
    note.content = content
    note.isSynced = false
    saveContext()
    queueForSync(note)
}

// Sync later when online
func syncNotes() {
    let unsyncedNotes = fetchUnsyncedNotes()
    for note in unsyncedNotes {
        api.upload(note) { success in
            if success {
                note.isSynced = true
                saveContext()
            }
        }
    }
}

Flutter (Hive + Background Worker)

// Save task offline
void addTask(String title) {
  final task = Task(title, false, DateTime.now(), false);
  hiveBox.add(task.toJson());
  queueForSync(task);
}
// Sync later
Future<void> syncTasks() async {
  final tasks = hiveBox.values.where((t) => t['synced'] == false);
  for (var task in tasks) {
    final success = await api.upload(task);
    if (success) {
      task['synced'] = true;
      hiveBox.put(task['id'], task);
    }
  }
}

Оба стека следовали одному и тому же правилу.

Локально в первую очередь. Синхронизация потом.

Сюрпризы

Я заставил мое приложение работать в офлайне - архитектурный сдвиг

Вот чего я не ожидал.

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

Уроки

  • Создавайте offline-first, и ваш онлайн-режим автоматически станет мощнее
  • Синхронизация — это не функция, а базовая архитектура
  • Разрешение конфликтов так же важно, как и дизайн
  • Уважайте свою локальную базу данных, она ваш лучший друг
  • Регулярно тестируйте офлайн, отключите Wi-Fi и посмотрите, что сломается

Заключение

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

Заставив своё приложение работать офлайн, я понял его истинную сущность.

Оно стало мощнее, быстрее и удобнее для пользователя.

И я усвоил один важный урок:

Интернет — это не фича. Это роскошь. Офлайн — это выживание.

Так что, если вы разрабатываете приложение в 2025 году, попробуйте один раз. Выключите Wi-Fi, откройте приложение и посмотрите, что получится.

Вот тогда и проявятся настоящие уроки архитектуры.

Источник

Если вы нашли опечатку - выделите ее и нажмите Ctrl + Enter! Для связи с нами вы можете использовать info@apptractor.ru.
Telegram

Популярное

Сообщить об опечатке

Текст, который будет отправлен нашим редакторам: