Работа с данными
Всё, что лежит между сервером и экраном: сам запрос, превращение ответа в модели, локальная копия и решение о том, что показывать, когда сеть медленная, отсутствует или врёт.
Почему это важно. Разница между демо и продуктом почти целиком здесь. Демо загружает и показывает. Продукт справляется со вторым нажатием, с устаревшим кешем, с поездкой через тоннель и с ответом, который приходит, когда пользователь уже ушёл дальше.
Что нужно понимать
- Где находится истина — на сервере, в кеше или, оптимистично, на экране
- Насколько устарели данные на экране и важно ли это здесь
- Что пользователь видит во время ожидания и нужно ли ожидание вообще
- Что сохраняется между запусками, а что сохранять нельзя
- Что происходит, когда одни и те же данные запрашиваются дважды одновременно
Основные темы
Загрузка
- Клиентский слой, который вызывают фичи, а не 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 — глава про репликацию и разрешение конфликтов, честный разбор того, что происходит, когда два устройства расходятся во мнениях.