Перейти к основному содержимому

Работа с данными

Всё, что лежит между сервером и экраном: сам запрос, превращение ответа в модели, локальная копия и решение о том, что показывать, когда сеть медленная, отсутствует или врёт.

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

Что нужно понимать

  • Где находится истина — на сервере, в кеше или, оптимистично, на экране
  • Насколько устарели данные на экране и важно ли это здесь
  • Что пользователь видит во время ожидания и нужно ли ожидание вообще
  • Что сохраняется между запусками, а что сохранять нельзя
  • Что происходит, когда одни и те же данные запрашиваются дважды одновременно

Основные темы

Загрузка

  • Клиентский слой, который вызывают фичи, а не HTTP, разбросанный по widget-ам
  • Сериализация и громкое падение на неожиданной структуре ответа
  • Отмена запроса, когда экран закрылся
  • Дедупликация одинаковых запросов, выполняющихся одновременно
  • Пагинация, включая скучные части: конец списка, обновление, вставка

Кеширование

  • Память, диск и разное время жизни у того и другого
  • Политики устаревания: fresh, stale-while-revalidate, cache-first
  • Инвалидация при записи — и шутка про две сложные задачи, которая оказывается правдой
  • Ключи кеша, которые учитывают пользователя и параметры
  • Кеширование изображений — отдельная история, о которой обычно уже позаботились

Локальное хранение

  • Ключ-значение для настроек, база данных — для всего, к чему нужны запросы
  • Миграции локальных схем: правила те же, что на сервере, но ломается всё неприятнее
  • Шифрование для чувствительных данных и то, что для этого даёт платформа
  • Размер хранилища и уборка за собой

Офлайн

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

Уровни

УровеньКак это выглядит
JuniorВызывает API, разбирает ответ, показывает состояния загрузки и ошибки.
MiddleСтроит слой данных с кешированием и пагинацией, сохраняет данные локально, обрабатывает отмену и дублирующиеся запросы.
SeniorПроектирует весь поток данных вместе с устареванием, инвалидацией и поведением офлайн — и в любой момент может сказать, где находится истина.

Практика

Для начала

  • Сделайте нормальную пагинацию Добавьте постраничную загрузку в список — вместе с концом списка, pull to refresh и ошибками посреди прокрутки.

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

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

Глубже

  • Stale while revalidate Покажите данные из кеша мгновенно, обновите их в фоне и подмените без мерцания.

  • Поставьте запись в офлайн-очередь Дайте пользователю действовать без сети и синхронизируйте изменения без дублей, когда сеть вернётся.

  • Разрешите конфликт Отредактируйте одну и ту же запись на двух устройствах и сделайте исход осознанным.

Проверьте себя

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

Материалы

  • Networking and data — официальная отправная точка по загрузке и разбору данных, включая разбор в фоновом изоляте.
  • Persist data with SQLite — путь через локальную базу данных, а рядом в cookbook — рецепты для ключ-значение и файлов.
  • Drift — типизированная локальная база данных для Dart. Её документация по миграциям и реактивным запросам — лучшее, что есть в экосистеме по локальному хранению.
  • Offline first — MDN о стратегиях работы офлайн. Написано для веба, но политики кеширования и схемы синхронизации переносятся один в один.
  • Designing Data-Intensive Applications — глава про репликацию и разрешение конфликтов, честный разбор того, что происходит, когда два устройства расходятся во мнениях.