🏗 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
👉 @golang_lib
В прошлом посте мы выяснили, что пакет 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
👉 @golang_lib
status_string.go