Сервер и клиент генерируются из .proto. Ручные изменения сгенерированных файлов теряются при следующей генерации, поэтому контракт и бизнес-логика разделены.

Инструменты

Нужны protoc и два плагина:

go install google.golang.org/protobuf/cmd/protoc-gen-go@latest
go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest

Пример генерации:

protoc --go_out=. --go-grpc_out=. proto/orders/v1/orders.proto

protoc-gen-go создаёт сообщения, protoc-gen-go-grpc создаёт клиент и серверный интерфейс.

сообщения .proto protoc-gen-go структуры Go вызовы .proto protoc-gen-go-grpc клиент и сервер

Один контракт порождает и типы сообщений, и код вызовов. Бизнес-логику пишут отдельно от сгенерированных файлов.

buf

buf упрощает настройку и проверки:

version: v2
generate:
  plugins:
    - name: go
      out: gen/go
    - name: go-grpc
      out: gen/go

Запуск buf generate повторяет одну и ту же генерацию для команды. buf lint проверяет оформление, а buf breaking ловит несовместимые изменения контракта.

Что менять руками

Сервер реализует сгенерированный интерфейс и при необходимости встраивает UnimplementedOrderServiceServer. Клиент получает OrderServiceClient. Эти типы не редактируют.

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

Версии и пакет

Плагины фиксируют в go.mod или lock-файле инструментов. Иначе latest на двух машинах даст разные версии генератора и большие необъяснимые diff-файлы. Обновление генератора делают отдельным изменением и проверяют получившийся код тестами.

Go-пакет задают в самом контракте:

option go_package = "example.com/orders/gen/ordersv1";

После генерации путь импорта единый для сервера и клиента. Если go_package не задан или конфликтует с out, файлы окажутся не там, где их ищет приложение. Поэтому генерацию запускают повторно на чистом checkout и проверяют, что рабочее дерево осталось без изменений: это ловит и старую версию .proto, и случайную ручную правку.

Коротко

  • Контракт в .proto, бизнес-логика в обычных Go-файлах.
  • protoc-gen-go отвечает за сообщения, protoc-gen-go-grpc за вызовы.
  • buf lint и buf breaking проверяют стиль и совместимость.
  • Сгенерированный код не правят вручную.