GH GambleHub

Обратная совместимость

Что такое обратная совместимость

Обратная совместимость (backward compatibility) — свойство системы принимать и корректно обрабатывать старых клиентов/потребителей, когда система обновляется. Проще: вы выпускаете новую версию сервиса/событий, а уже существующие интеграции продолжают работать без изменений.

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

Базовые принципы

1. Additive-first

Новые поля/методы/события добавляются опционально. Ничего существующего не удаляется и не меняет смысл.

2. Минимальный гарантийный контракт (MGC)

Определите ядро — набор полей/операций, без которых сценарий теряет смысл. Ядро стабильно. Все остальное — расширения.

3. Tolerant reader

Клиенты игнорируют неизвестные поля и корректно обрабатывают новые значения enum (fallback).

4. Политика версий

Ломающие изменения — только через major-линию (`/v2`, `payments.v2`, `event.v2`). Минорные — аддитивны.

5. Наблюдаемость — часть контракта

В логах/трейсах и метриках видны версия клиента, формат, capability-флаги. Это позволяет управлять миграцией.

Безопасные vs опасные изменения

Обычно безопасны (BC-OK)

Добавление необязательных полей (JSON/Avro/Protobuf `optional`/`nullable`).
Добавление новых эндпоинтов/методов/событий.
Расширение enum дополнительными значениями (при tolerant reader).
Ослабление валидации (увеличение максимумов, добавление альтернативных форматов).
Добавление заголовков/метаданных, не влияющих на смысл.

Опасны (Breaking)

Удаление/переименование полей, изменение типа или обязательности существующих полей.
Смена семантики статусов/кодoв ошибок.
Переиспользование protobuf-тегов под другие поля.
Смена ключа партиционирования события (ломает порядок для агрегата).
Ужесточение SLA/таймаутов, из-за чего старые клиенты начинают падать.

По стилям взаимодействия

REST/HTTP + JSON

Аддитивность: новые поля — `optional`, сервер не требует их от старых клиентов.
Версии: major — в пути (`/v2`) или медиатипе; minor — через расширения и `?include=`/`?fields=`.
Ошибки: единый формат; не менять коды/семантику без major.
ETag/If-Match: для безопасных апдейтов без гонок.
Идемпотентность: `Idempotency-Key` для POST — старые клиенты не «удваивают» эффект при ретраях.

gRPC / Protobuf

Теги неизменны. Удаленные теги не переиспользовать.
Новые поля — `optional`/`repeated`; значения по умолчанию корректно обрабатываются старым кодом.
Стриминг: не менять порядок/обязательность сообщений в рамках minor.
Ошибки — стабильный набор статусов; новая семантика → новый метод/сервис (`.v2`).

Event-driven (Kafka/NATS/Pulsar) + Avro/JSON/Proto

Именование: `domain.action.v{major}`.
Core vs Enriched: ядро стабильно; обогащения — отдельные типы/темы (`.enriched`).
Режим совместимости схем: чаще BACKWARD; CI блокирует несовместимые изменения.
Партиционирование: ключ (например, `payment_id`) — часть контракта; менять его — breaking.

GraphQL

Добавление полей/типов — ОК; удаление/переименование — через `@deprecated` и окно миграции.
Не повышайте «nullable → non-nullable» без major.
Контролируйте complexity/depth — изменение лимитов = изменение контракта.

Паттерны, помогающие сохранить BC

Модель обратной пирамиды: стабилизируйте ядро, расширяйте опционально.
Capability negotiation: клиент сообщает поддерживаемые возможности (`X-Capabilities`/handshake), сервер подстраивается.
Dual-run / dual-emit: на время миграции держите одновременно `v1` и `v2`.
Адаптеры: прокси/гейтвей переводят запросы `v1↔v2` для «тяжелых» клиентов.
Expand-and-contract (для БД): сначала добавьте новое, начните писать/читать, только потом удаляйте старое.

Governance и процесс

1. Каталог контрактов (реестр схем): единый источник истины с политиками совместимости.
2. Линтеры и дифф-чеки в CI/CD: OpenAPI-diff, Buf-breaking, проверка совместимости Avro/JSON Schema.
3. CDC/Consumer-Driven Contracts: провайдер проверяется на реальные контракты потребителей.
4. Golden samples: эталонные запросы/ответы/события для регресса.
5. Change management: RFC/ADR на breaking, планы sunset, коммуникация.

Депрекейт и снятие старых версий

Пометьте устаревшее (`@deprecated`, описания, заголовки `Deprecation`, `Sunset`).
Окно миграции: заранее объявленная дата, тестовый стенд, примеры кода.
Телеметрия использования: кто еще на `v1`? сегментируйте метрики/логи по версии.
Dual-run до нуля трафика, затем — удаление.

Наблюдаемость и операционные метрики

Процент запросов/сообщений по версиям.
Доля ошибок/таймаутов у старых клиентов после релиза.
Доля несовместимых payload (валидация схемой на шлюзе/стрим-фильтрах).
Лаг миграции потребителей (сколько еще слушают `v1`).

Тестирование обратной совместимости

Schema-diff: fail при remove/rename/type-change.
Контракт-тесты: старые SDK/клиенты гоняются против новой реализации.
E2E-канарейка: часть старого трафика на новую версию, сравнение p95/p99, кодов, ретраев.
Реплей событий: проекции собираются новой логикой из старого лога без расхождений.
Fault-injection: задержки/частичные ответы — старые клиенты не падают.

Примеры

REST (аддитивно)

Было:
json
{ "id": "p1", "status": "authorized" }
Стало:
json
{ "id": "p1", "status": "authorized", "risk_score": 0. 12 }

Старые клиенты, игнорируя `risk_score`, продолжают работать.

Protobuf (теги)

proto message Payment {
string id = 1;
string status = 2;
optional double risk_score = 3 ;//new field, safe
}
//Tags 1 and 2 cannot be changed/deleted without v2

События (ядро + обогащение)

`payment.authorized.v1` — ядро (минимум фактов).
`payment.enriched.v1` — детали; потребители ядра не зависят от обогащений.

Антипаттерны

Swagger-wash: обновили схему, но сервис ведет себя по-старому (или наоборот).
Скрытые ломки: поменяли смысл поля/статуса без версии.
Переиспользование protobuf-тегов: «тихая» коррупция данных.
Жесткие клиенты: падают на незнакомых полях/enum; нет tolerant reader.
Mega-endpoint: одно все-в-одном — любое изменение становится потенциальной ломкой.

Чек-лист перед релизом

  • Изменения аддитивны; ядро (MGC) не тронуто.
  • Линтеры/дифф-чеки пройдены; breaking-флагов нет.
  • Клиентские SDK обновлены (или не требуются для аддитивного расширения).
  • Включен tolerant reader у клиентов; enum-fallback проверен.
  • Метрики/логи содержат версию и capability-флаги.
  • Для потенциальной ломки есть `/v2`, dual-run и план sunset.
  • Документация/примеры обновлены, есть golden-наборы.

FAQ

Backward vs forward — в чем разница?
Backward — новые серверы работают со старыми клиентами. Forward — новые клиенты корректно работают со старыми серверами (за счет tolerant reader и аккуратных дефолтов). Полный круг — full compatibility.

Нужно ли всегда делать `/v2` для больших изменений?
Да, если ломаются инварианты/типы/ключи/семантика. Иначе — сохраняйте линию и эволюционируйте аддитивно.

Как быть с enum?
Добавляйте новые значения, не меняя смысл старых. Клиенты должны иметь fallback при неизвестном значении.

Что делать, если уже «сломали»?
Откат, hot-fix адаптер, выпуск `v2` с dual-run, коммуникация и миграционный гайд.

Итог

Обратная совместимость — это дисциплина эволюции: стабилизируйте ядро, расширяйте аддитивно, внедряйте tolerant reader, автоматизируйте проверки и ведите осознанный депрекейт. Так вы сможете быстро развивать платформу, не оставляя клиентов под обломками «незаметных» изменений.

Contact

Свяжитесь с нами

Обращайтесь по любым вопросам или за поддержкой.Мы всегда готовы помочь!

Начать интеграцию

Email — обязателен. Telegram или WhatsApp — по желанию.

Ваше имя необязательно
Email необязательно
Тема необязательно
Сообщение необязательно
Telegram необязательно
@
Если укажете Telegram — мы ответим и там, в дополнение к Email.
WhatsApp необязательно
Формат: +код страны и номер (например, +380XXXXXXXXX).

Нажимая кнопку, вы соглашаетесь на обработку данных.