Экран с коэффициентом выглядит как обычная карточка, но в приложении это лишь проекция состояния, которое уже прошло несколько границ. Полезнее проектировать путь не от макета к API, а от вопроса: какое значение считается источником истины на каждом шаге и когда клиент обязан запросить подтверждение заново?
Четыре контура вместо одного «backend»
Каталог событий, поток котировок, состояние бетслипа и транзакционное подтверждение живут с разной частотой обновления. Если связать их одним общим кэшем или одинаковым TTL, быстрые изменения рынка начинают конфликтовать с более медленными справочными данными. Поэтому границы лучше проводить по ответственности: витрина отвечает за навигацию, pricing — за актуальную цену, бетслип — за состав выбора, а финальная операция — за атомарное подтверждение условий.
Повтор действия не должен создавать новую операцию
Мобильная сеть меняется, приложение уходит в фон, пользователь нажимает кнопку ещё раз. На этом участке важна идемпотентность: повтор запроса должен либо вернуть состояние уже начатой операции, либо безопасно сообщить, что подтверждение больше невозможно. В логах при этом нужен единый correlation ID, связывающий клиентский запрос с API и последующей серверной обработкой.
Цена изменилась — это отдельное состояние
Нельзя сводить loading, suspended, unavailable и price changed к одному универсальному alert. Они требуют разных действий. При смене цены интерфейс должен показать новое условие и запросить явное подтверждение; при suspend действие временно недоступно; при unavailable выбор нужно удалить или заменить. Такая модель состояний полезнее декоративной анимации «обновляется».
Что измерять после релиза
Среднее время ответа мало говорит о корректности сценария. Полезнее сопоставлять freshness данных, долю успешно завершённых подтверждений, частоту повторных запросов и распределение ошибок по конкретным state transition. Тогда деградация метрики сразу указывает, какой компонент исследовать.
- зафиксировать источник истины для цены и статуса рынка;
- сделать подтверждение идемпотентным;
- протянуть correlation ID через клиент и backend;
- развести пользовательские состояния по смыслу, а не по одному цвету ошибки.
Где фиксировать авторитетное состояние
Мобильный клиент быстро становится сложным, если одни значения считаются авторитетными на устройстве, а другие — на сервере без чёткой границы. Счёт и состояние рынка должны приходить из согласованного backend-контура, а локальный кэш нужен прежде всего для скорости отображения и восстановления интерфейса. При reconnect клиенту важнее получить свежий snapshot, чем пытаться бесконечно доигрывать собственную историю изменений.
Контрольные вопросы
- помечать данные временем получения и версией состояния
- не смешивать спортивный факт и состояние коэффициента в одном поле обновления
- после reconnect сверять локальное состояние с серверным snapshot
- логировать путь запроса от UI до сервиса подтверждения
Практическая проверка — открыть один и тот же рынок на двух устройствах, искусственно задержать обновления на одном из них и посмотреть, где интерфейс начинает расходиться. Такая проверка быстро показывает, какой слой на самом деле управляет состоянием.
Авторитетное состояние нужно определить до разработки экранов
Когда один и тот же market одновременно существует в provider feed, нормализованном storage, pricing service, cache и мобильном клиенте, слово «текущая цена» становится двусмысленным. Команда должна заранее решить, какой слой считается authoritative для каждой операции. Для отображения можно использовать кэшированную версию, но подтверждение действия должно опираться на состояние, которое сервер способен однозначно идентифицировать и проверить. Иначе расследование спорного reprice сводится к сравнению скриншота с логами нескольких компонентов без общей версии.
Эта граница тесно связана с тем, как система обрабатывает out-of-order события, corrections и replay. Если upstream прислал correction, приложение не должно получать «новую» картинку из одного слоя и «старое» подтверждение из другого. Поэтому версия, event time и причина обновления полезны не только backend-команде: они позволяют API и клиенту понимать, что состояние действительно сменилось, а не просто было заново отдано из другого кэша.
На практике полезен простой тест: выбрать один live market и проследить его путь от входного события до отрисованного состояния, записав идентификаторы версий на каждой границе. Если хотя бы на одном участке связь приходится восстанавливать по приблизительному времени, именно там будущий инцидент будет разбираться дольше всего.
Для документации полезно хранить не абстрактную схему из прямоугольников, а один сквозной пример с реальными типами идентификаторов: provider event, canonical event, market version, pricing version, API response и client state. Такой пример быстро обнаруживает места, где version теряется или переименовывается. Он же помогает при изменении интеграции: команда видит, какой контракт затронут и какие downstream-компоненты должны подтвердить совместимость до релиза.
