Legacy и миграции

·4 мин чтения·Обновлено

Backward Compatibility: новый код должен пережить старых клиентов

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

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

Backward Compatibility означает, что новая сторона продолжает выполнять прежний договор с поддерживаемыми потребителями. Здесь недостаточно сохранить адрес API и названия полей. В договор входят смысл ответа, допустимые действия, ошибки и условия, при которых клиент считает работу законченной.

Сначала назвать версии, которым обещана совместимость

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

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

Google AIP-180 различает совместимость исходного кода, обмена и смысла. Это помогает сформулировать обещание точнее: приложение может успешно разобрать ответ, но сделать на его основании совсем не то, что предполагалось раньше.

Дополнительное поле тоже может изменить результат

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

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

Добавление нового статуса также требует знания потребителя. Одно приложение покажет «состояние неизвестно», другое завершится с ошибкой, третье выберет небезопасную ветку по умолчанию. Рекомендации Zalando отдельно обсуждают расширяемость значений и правила совместимых изменений. Название типа string не описывает все ожидания клиента.

Иногда старый договор принципиально не умеет выразить новую реальность. Если прежде поставка принималась целиком, а теперь допускается приёмка части коробок, нельзя без потерь свести любое новое состояние к «принято» или «не принято». Потребуется новый сценарий, ограничение старого клиента или явное обновление контракта. Придуманное приблизительное значение может быть опаснее понятного отказа.

Подготовить чтение до появления новой записи

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

Такой двухэтапный выпуск разобран в Amazon Builders’ Library. Важная граница: после появления нового формата вернуться можно только к программе, способной его прочитать. Наличие сохранённого установочного пакета ещё не означает безопасного возврата.

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

Проверить реальных потребителей, а не только последнюю сборку

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

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

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

Старый контракт не обязан жить вечно

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

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

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