go generate: Как писать код, который пишет код (и побеждает рефлексию)В прошлом посте мы выяснили, что пакет
reflect - это медленно и опасно. Но как тогда писать универсальные инструменты? Валидаторы, парсеры, моки для тестов?В языках вроде Rust есть мощные макросы. В Java - аннотации и байт-код магия. В Go создатели пошли по пути брутальной простоты и дали нам Кодогенерацию.
Идея звучит как лозунг киберпанка: "Пусть программа сама напишет для нас скучный код ДО того, как мы её скомпилируем".
Как работает
//go:generateВ Go встроен специальный механизм. Если вы напишете в любом файле магический комментарий (строго без пробела после
//), тулчейн сможет его найти и выполнить.Возьмем классическую боль Go - "энумы" (перечисления). У нас есть статусы заказа, и мы хотим красиво выводить их в логи:
package order
//go:generate stringer -type=Status
type Status int
const (
Created Status = iota
Paid
Shipped
)
Вы открываете терминал, вводите одну команду:
go generate ./...
И тулчейн находит ваш комментарий, запускает утилиту
stringer, которая за миллисекунду генерирует рядом файл status_string.go. В нем лежит гигантский, тупой, но молниеносно быстрый switch, который превращает ваши константы в строки.Никакой рефлексии. Никакого парсинга в рантайме. Чистый, скомпилированный машинный код.
Почему Кодогенерация > Рефлексии в HighLoad?
1. Скорость: Сгенерированный код работает в 10-50 раз быстрее рефлексии (вспомните
easyjson против encoding/json).2. Безопасность: Если структура изменилась, а сгенерированный код устарел - у вас просто не соберется проект. Компилятор ударит по рукам. При рефлексии вы узнаете об ошибке только когда код упадет с паникой на проде.
3. Читаемость: Сгенерированный код можно прочитать глазами, поставить брейкпоинт и отладить по шагам. Отладить кишки
reflect.Value - задача для сильных духом.Где это используют каждый день?
• Тесты (
mockgen / vektra/mockery): Генерация моков для интерфейсов. Никто не пишет заглушки руками.• Базы данных (
sqlc): Вы пишете чистый SQL-запрос в файл .sql, а утилита генерирует под него Go-структуры и типобезопасные функции.• API (
oapi-codegen / protoc): Генерация HTTP-роутеров и структур из OpenAPI (Swagger) или gRPC/Protobuf контрактов.🔥 Senior Tip: Коммитить ли сгенерированный код в Git?
Вечный холивар. Вы сгенерировали 10 000 строк моков. Нужно ли пушить их в репозиторий?
Официальный ответ от команды Go: ДА.
Сгенерированный код нужно коммитить. Это гарантирует, что любой разработчик (или CI-сервер) сможет просто сделать
go build или go test, не устанавливая себе локально на ноутбук зоопарк специфичных кодогенераторов нужных версий.Кодогенерация - это легальный чит-код в Go. Вы пишете меньше кода, а программа работает быстрее.
#golang #architecture #performance #codegen #bestpractices
📲 Мы в MAX
👉 @golang_lib