АналитикаСистемный анализСистемный аналитик

Сервису требуется изменить несовместимое поле в API, но клиенты обновляются не одновременно. Как организова...

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

Проходите собеседования с ИИ помощником Hintsage

Краткий ответ

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

Исторический контекст

API часто используют независимо развиваемые клиенты: мобильные приложения, веб-интерфейсы, партнёрские системы и внутренние сервисы. Их релизы не происходят одновременно, поэтому изменение формата ответа или смысла поля может сломать часть потребителей.

Версионирование появилось как способ управлять эволюцией распределённого контракта. Оно отделяет изменения поставщика API от жизненного цикла клиентов и делает несовместимость явной, а не случайной.

Постановка проблемы

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

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

Подробное решение

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

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

Переход обычно включает несколько этапов:

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

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

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

Ситуация из практики

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

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

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

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

Что кандидаты часто упускают

  1. Достаточно ли добавить новую версию в адрес API, чтобы обеспечить безопасную миграцию?

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

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

  1. Когда изменение поля можно считать обратно совместимым?

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

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

  1. Что делать, если после объявления срока прекращения старой версии один потребитель всё ещё использует её?

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

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