Семантическое версионирование
Semantic Versioning (SemVer) — договор о том, как номер версии отражает характер изменений. Формат: MAJOR.MINOR.PATCH[-PRERELEASE][+BUILD].
Смысл:- MAJOR — несовместимые изменения (breaking).
- MINOR — обратноссовместимые фичи/расширения.
- PATCH — обратноссовместимые исправления ошибок/безопасности.
Цель: предсказуемая эволюция API, событий, схем данных, SDK и конфигов без внезапных поломок потребителей.
1) Конвенция номеров
X.Y.Z[-alpha.1 -rc.1][+build.sha]
Pre-release (`-alpha`, `-beta`, `-rc`) — нестабильные сборки; не обещают совместимости.
Build metadata (`+sha`) — не влияет на порядок сравнения, полезно для трассировки.
До 1.0.0 любое изменение может считаться breaking (но лучше соблюдать правила с самого старта).
2) Что считать breaking/minor/patch
PATCH (Z):- Фиксы багов и безопасности без смены контракта.
- Док-апдейты, не затрагивающие контракт.
- Оптимизации без изменения ответов/событий/схем.
- Добавление новых необязательных полей/методов/эндпоинтов.
- Расширение enum значениями, если потребители терпимы к незнакомым значениям.
- Новые индексы БД, колонки nullable с дефолтом, новые события дополнительно к старым.
- Удаление/переименование полей, изменение типов, обязательности.
- Изменение семантики/статусов/кодов ошибок.
- Смена формата сериализации, схемы ключей, протокола транспорта.
- Сжатие/слияние топиков, перенос смысла события, изменение схемы партиционирования.
- Миграции БД, требующие «двухфазного» переключения без обратной совместимости.
3) Версионирование по артефактам
3.1 REST
Варианты: `URI /v1/...`, заголовки (`Accept: application/vnd.acme.game+json;version=1`), параметр.
Рекомендация: версия в URI для публичных API; для внутренних — через заголовок c negotiation.
MINOR: добавление необязательных полей, новых фильтров/ресурсов; не меняйте существующие ответы.
PATCH: фиксы, уточнение описаний, стабильные сортировки.
3.2 gRPC
Смена сигнатур/типов → MAJOR (новый пакет/служба: `acme.wallet.v2`).
Новые поля — с меткой optional; сервер должен игнорировать неизвестные.
Поля не удаляем: «деприкейт + зарезервировать номер», удалить — только в следующем MAJOR.
3.3 GraphQL
MINOR: новые поля/типы/query; удаление — через `@deprecated` + окно миграции, полноценное удаление — MAJOR.
Изменение nullable→non-nullable — MAJOR.
3.4 События и топики (Kafka/SQS)
Схемы в Schema Registry: эволюция additive (добавлять поля с дефолтами).
Новая несовместимая версия → новый subject/topic (`bet.settled.v2`).
Ключ партиционирования неизменен внутри MAJOR.
3.5 Схемы БД
«Расширяй, затем сворачивай»:1. Добавить колонку (nullable/с дефолтом) →
2. Заполнить бэкфилл →
3. Перевести чтения →
4. Убрать старое (только в MAJOR).
Изменение типа/PK/уникальностей — MAJOR, под фичефлагом и двойной записью.
3.6 SDK/CLI
Публичные методы/сигнатуры — те же правила.
Для автогенерации (OpenAPI/Proto) — версия пакетного имени и артефактов.
4) Политика деприкаций и жизненный цикл
Каждому breaking-изменению предшествует деприкация (обычно 90–180 дней для внешних, 30–60 — для внутренних).
Коммуникации: changelog, e-mail/вебхуки партнерам, баннеры в портале разработчика.
Режим dual-run: параллельно держим `v1` и `v2`, мониторим долю трафика `v1`.
Sunset headers (REST): `Sunset: 2026-03-31`, `Link: <url>; rel="deprecation"`.
5) Version negotiation
Клиент отправляет желательную версию + максимальную поддерживаемую (например, `Accept-Version: 1,2`).
Сервер отвечает `Content-Version: 2`, если смог повысить.
В двунаправленных протоколах (WebSocket, gRPC) — обмен Hello-фреймами с `supported_versions`.
6) Интеграция с адаптерами провайдеров (ACL)
Внешний провайдер меняет схему — внутри адаптера держим мэпперы v1/v2 и выпускаем MINOR для внутреннего события, сохраняя наш доменный контракт.
Если внешние изменения пробиваются внутрь — это MAJOR нашего доменного события и новый subject.
7) Changelog и метки коммитов
Следуем Keep a Changelog и Conventional Commits:- `feat:...` → MINOR
- `fix:...` / `chore`, `docs`, `perf` (без контракта) → PATCH
- `feat!:` / `fix!:` / `refactor!:` или `BREAKING CHANGE:` в теле → MAJOR
[2.3.0] - 2025-10-31
Added
- GET /v1/games?capabilities=jackpot (optional)
Changed
- GraphQL: field Game.volatility @deprecated, use Game.riskProfile
8) Автоматизация релизов
CI: валидаторы схем (OpenAPI/Protobuf/Avro/JSON-Schema), детект breaking-диффов.
SemVer-бот: анализ Conventional Commits → вычисляет bump (major/minor/patch), проставляет тег, генерит changelog.
CD: раздельные deploy и release (фичефлаги/конфиги активируют новую версию).
Контроль: не публикуем `latest` на PRO до успешных canary и согласованных SLO.
9) Семантика для конфигураций и политик
Конфиги (YAML/JSON) тоже имеют версию схемы: `schema_version: 3`.
MINOR — новые необязательные поля/правила; MAJOR — смена структуры/обязательности.
Поддержка v2/v3 в валидаторе; мигратор конфигов с отчетом несовместимостей.
10) Тестирование совместимости
Consumer-driven contract tests (Pact): на каждую интеграцию.
Schema-evolution tests: прогон старых payload’ов на новой схеме и наоборот.
Replay: воспроизведение прод-трафика `v1` на `v2` в тени.
Property-based: устойчивость к незнакомым полям/enum.
11) Наблюдаемость по версиям
Тэгируйте метрики/логи: `api_version`, `schema_version`, `event_version`.
Дашборды миграции: доля трафика по версиям, ошибка/латентность по `v1/v2`.
Алерты: если `v1` не снижается по плану; рост 4xx/5xx после выпуска `v2`.
12) Миграционные паттерны без простоев
Expand → Migrate → Contract (БД).
Dual write + сравнение дивергенций перед переключением чтения.
Shadow compare для ранжирования/правил.
Canary по тенантам/регионам; feature flags для быстрых откатов.
Read-compat / Write-compat окна: новая версия читает старые данные, но пишет в новом формате.
13) Анти-паттерны
«Версия в каждом поле» вместо версионирования ресурса/события.
Скрытые breaking-изменения под MINOR (например, изменение дефолтов).
Удаление деприкейтнутого без окна и метрик потребления.
«Навсегда v1»: отсутствие плана снятия старых версий → техдолг и уязвимости.
Смешение бизнес-версии и версии контейнерного образа.
14) Чек-лист политики версионирования
- Зафиксирован формат версий и источники истины (Registry/Portal).
- Утвержден список breaking-критериев по артефактам (REST/gRPC/GraphQL/events/DB).
- Процесс деприкаций: сроки, коммуникации, sunset/баннеры, dual-run.
- Автоматический diff-чекер схем и Conventional Commits.
- Дашборды потребления версий и алерты.
- Плейбуки миграции (expand/migrate/contract, dual-write, shadow).
- Конфиги и SDK имеют собственные версии и регистр.
- Документация «как выбрать версию» для клиентов и «как повышать» для команд.
15) Примеры версионирования (iGaming-кейсы)
Событие `BetSettled v1` → `v2`: добавили `void_reason` (optional) и `tax.amount` (optional) — MINOR. Переназвали `payout`→`win_amount` — MAJOR, новый subject.
REST `/wallets/transfer`: добавили фильтр `?tenant_id=` — MINOR. Изменили код ошибки `409`→`422` — MAJOR.
GraphQL: пометили `Player.age` как `@deprecated` в пользу `Player.ageGroup` — выпуск в MINOR, удаление в MAJOR после периода X.
БД: добавили колонку `bonus_wager_left` nullable — MINOR. Сделали non-null и удалили `bonus_left` — MAJOR (через expand/contract).
Заключение
Семантическое версионирование — это не про цифры, а про доверие и предсказуемость. Четкие правила, автоматические проверки, контролируемые деприкации и прозрачная телеметрия позволяют эволюционировать API, события и схемы без боли для интеграций — и выпускать изменения часто, безопасно и осмысленно.