Перейти к содержанию

Состояние реактивных интерфейсов

Требования применяются к пользовательским интерфейсам frontend- и нативных mobile-компонентов, в которых представление вычисляется из изменяемого состояния. Они не предписывают framework, библиотеку или именованный архитектурный паттерн. Уровни обязательности определены в корневом README.md.

В этом документе:

  • владелец состояния — проектный компонент, который принимает операции изменения конкретной части состояния и определяет срок её жизни;
  • производное состояние — значение, полностью вычисляемое из другого состояния;
  • эффект — операция вне вычисления представления: сетевой вызов, запись, подписка, таймер, аналитическое событие или обращение к системному API;
  • намерение — последнее принятое действие пользователя или системы, задающее ожидаемый результат для затронутой части интерфейса.

UI-STATE-001. Единственное владение изменяемым состоянием

Уровень: MUST

Применяется к: каждой изменяемой части состояния, влияющей на представление или доступное пользователю действие

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

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

Обоснование

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

Проверка

  • unit-тест операций владельца и вычисления производных значений;
  • статическая проверка прямых записей в состояние вне владельца;
  • component-тест смены субъекта, маршрута или входных параметров.

Исключения

Независимая локальная копия MAY существовать для редактирования до явного подтверждения, если определены исходная версия, операция применения и поведение при конфликте.

UI-STATE-002. Различимые состояния асинхронной операции

Уровень: MUST

Применяется к: асинхронной операции, результат которой влияет на представление или доступное пользователю действие

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

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

Обоснование

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

Проверка

  • параметризованный test переходов между применимыми состояниями;
  • component- или UI-тест загрузки, пустого результата, отказа и отмены;
  • тест обновления при наличии ранее полученных данных.

Исключения

Синхронное вычисление без ожидания и отказного исхода находится вне области требования.

UI-STATE-003. Жизненный цикл эффектов

Уровень: MUST

Применяется к: эффекту, инициируемому пользовательским интерфейсом

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

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

Обоснование

UI runtime может повторять вычисление представления и пересоздавать его части; неуправляемый эффект вызывает дублирование операций и удержание ресурсов.

Проверка

  • component-тест повторного render или recomposition;
  • тест размонтирования, ухода с экрана и отмены родительской операции;
  • проверка освобождения подписок, наблюдателей и таймеров;
  • тест отсутствия повторного необратимого эффекта.

Исключения

Эффект уровня приложения MAY переживать отдельный экран, если его владелец явно находится на уровне приложения и завершает эффект при остановке сессии или процесса.

UI-STATE-004. Конкурирующие результаты и optimistic update

Уровень: MUST

Применяется к: двум или более одновременно выполняемым операциям, способным изменить одну часть пользовательского состояния

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

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

Обоснование

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

Проверка

  • детерминированный тест завершения операций в обратном порядке;
  • тест отмены и позднего результата;
  • тест подтверждения, отказа и конфликта optimistic update;
  • проверка сохранения несвязанных более новых изменений.

Исключения

Параллельные операции над доказуемо независимыми частями состояния могут приниматься независимо.

UI-STATE-005. Стабильная идентичность элементов

Уровень: MUST

Применяется к: изменяемой коллекции элементов, для которых UI runtime сохраняет локальное состояние, фокус, ввод или выполняемый эффект

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

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

Обоснование

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

Проверка

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

Исключения

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