API
gRPC и Protobuf: построй контракт, переживающий эволюцию
Читать про порчу field tag — не то же самое, что удержать живой контракт целым через деплой. Построй небольшой gRPC-сервис, затем эволюционируй его схему так, как тебя вынуждает реальная система — старые клиенты ещё в полёте, новые поля приземляются, удалённое поле, которое никогда не должно вернуться — и докажи запущенными пирами, что ничего не декодировалось в неверный слот.
Преврати ментальную модель юнита в рабочий контракт: определи proto, запусти две версии сервиса бок о бок, эволюционируй схему add-only с reserved, добавь streaming RPC по правильной причине и продемонстрируй, что deadlines распространяются и отменяют работу по графу вызовов.
Построй небольшой gRPC-сервис (Go или любой язык со зрелым gRPC-стеком), эволюционируй его схему Protobuf через две версии, которые должны взаимодействовать в обе стороны, добавь один streaming RPC и докажи — двумя запущенными пирами и захваченными доказательствами — что эволюция схемы остаётся безопасной и deadlines распространяются.
- Воспроизводимая матрица совместимости (команды + захваченный вывод), доказывающая взаимодействие v1-v2 в обе стороны с нулём недекодированных полей.
- Захваченный вывод ветки намеренного слома, показывающий, что перенумерация/переиспользование портит значение, плюс откатанный main, где reserved блокирует переиспользование на этапе компиляции.
- Streaming RPC работает против реального клиента, а обоснование в одно предложение называет, кто стримит, и почему более простая форма отвергнута.
- Захваченный DEADLINE_EXCEEDED у клиента для вызова в медленный downstream, с доказательством, что deadline распространился, а не каждый хоп таймаутился независимо.
- Добавь CI-гейт через buf breaking (или protolock), который диффит proto против закоммиченного baseline и валит сборку на любом wire-несовместимом изменении — перенумерация, смена типа или нерезервированное удаление.
- Добавь grpc-web или Connect-путь для браузерного клиента и задокументируй, что именно добавляет слой прокси/трансляции и какие формы streaming он не поддерживает.
- Добавь FieldMask (или optional-поля) для поддержки настоящей PATCH-семантики и покажи, как сервер отличает «очищено в пустое» от «не прислано» на скалярном поле.
- Забенчмарь один и тот же payload как protobuf против JSON для насыщенного числами и насыщенного строками сообщения и отчитайся о дельте размера/задержки, чтобы подтвердить, где выигрыш wire format реален.
Это цикл, который ты прогоняешь всякий раз, когда gRPC-контракт должен меняться под живым трафиком: эволюционируй add-only, резервируй каждое удаление и проверяй двумя запущенными пирами, что обе стороны всё ещё декодируют корректно — затем докажи себе, один раз, что перенумерация действительно портит, чтобы дисциплина стала мышечной памятью. Выбирай формы streaming по тому, кто реально стримит, ставь deadlines, которые распространяются и отменяют downstream-работу, и держи gRPC там, где ему место — между твоими сервисами, с REST/Connect на браузерной границе.