В мире Go произошли серьёзные изменения, и речь идёт не о небольших патчах или минорных доработках, а о действительно важном нововведении: в версии Go 1.24 появилась команда go tool и новая директива tool в go.mod. Многие разработчики называют это одним из наиболее значимых улучшений Go за последние годы. Почему эта функция кажется такой важной, как она работает и что нам всем следует об этом знать — давайте разбираться подробнее.
Почему мы ждали этого столько времени
Если вы когда-либо работали над крупным проектом на Go, вы наверняка сталкивались с ситуацией, когда необходимо использовать внешние инструменты для:
🔧 Генерации кода (например, oapi-codegen, gqlgen, sqlc и т. д.).
🧪 Прогона тестов со специальными форматами отчётов (JUnit, HTML).
🚀 Деплой-скриптов и других утилит, необходимых для CI/CD.
До Go 1.24 эти утилиты можно было подключать по-разному:
- Либо разработчик знал и сам ставил нужный инструмент через go install (или через некую обёртку типа make deps).
- Либо использовался «трюк» с файлом tools.go, который явно импортировал нужные пакеты. Тогда при запуске go run (или go generate) эти пакеты устанавливали необходимые бинарники.
Однако такой подход имел ощутимые недостатки:
🐢 Падение производительности при многократном go run: особенно на больших проектах, где задействовано много таких вызовов в цепочке генерации кода.
📦 Избыточность зависимостей в go.mod: все «инструментальные» пакеты попадали в список зависимостей и появлялись у конечных пользователей модуля как транзитивные (хотя им не нужны).
Новая команда go tool и директива tool в go.mod призваны исправить эти проблемы. Теперь инструменты можно подключать аккуратно, не засоряя список зависимостей основной библиотеки, а запуск — кешировать так, чтобы не приходилось пересобирать всё заново при каждом вызове.
Как это устроено на практике
Подготовка проекта
С выходом Go 1.24 в корне вашего проекта нужно:
- Обновить версию Go в go.mod, например:
module myawesomeproject
go 1.24
Можно также указать нужную версию через toolchain, если пользуетесь более свежим механизмом:
toolchain go1.24
Затем «подключить» инструмент, который хотите использовать. Например, если вам нужен oapi-codegen:
go get -tool github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen@v2.4.1
Эта команда добавит в ваш go.mod директиву:
tool github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen
и запишет зависимость на пакет oapi-codegen как indirect — то есть система понимает, что он нужен не для конечной сборки вашего приложения, а только как вспомогательный инструмент.
Запуск инструментов
Раньше в tools.go или непосредственно в комментариях к go:generate мы писали что-то вроде:
go run -modfile=tools/go.mod github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen ...
Теперь же всё упрощается до:
go tool github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen ...
А в аннотации go:generate это может выглядеть так:
//go:generate go tool github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen --config=config.yaml openapi.yaml
В результате — меньше «ритуальных» действий, код выглядит чище, а самое главное — Go кэширует сборку инструмента, поэтому при повторных запусках всё работает быстрее.
Настройка кеширования и прирост производительности
В версии Go < 1.24 кэширование для команд go run было довольно ограниченным. При частых генерациях кода (например, когда вы запускаете oapi-codegen на нескольких разных схемах OpenAPI подряд) приходилось снова и снова пересобирать бинарник. Теперь же:
⚡ Первая сборка может занять некоторое время, поскольку Go создаст кешированный бинарник инструмента.
🔥 Повторные запуски выполняются практически мгновенно, так как уже собранный инструмент берётся из кеша.
Разработчики отмечают, что на крупных кодовых базах в CI/CD-пайплайнах это сокращает время сборки и тестирования. А если учесть, что какие-то инструменты (типа gqlgen, sqlc, golangci-lint) могут запускаться десятки раз в сутки, экономия становится внушительной.
Краткий обзор «подводных камней»
Несмотря на позитивные изменения, есть несколько моментов, которые стоит учесть:
🧩 Формирование зависимостей: инструменты всё равно учитываются в go.mod как indirect. При неаккуратном обновлении (например, с помощью автоматизированных тулов типа Renovate), можно столкнуться с тем, что indirect-зависимости подтягиваются в неподходящих версиях.
❓ Совместимость некоторых инструментов: упоминается, что gqlgen может работать нестабильно с ранними RC Go 1.24. Возможно, это баг в Go itself или комбинация зависимостей. Если вы внедряете новую версию Go сразу после её релиза, будьте готовы к тому, что не все инструменты окажутся совместимы «из коробки».
🔒 Дистрибутивные бинарники vs. сборка из исходников: такие проекты как golangci-lint советуют использовать предсобранные бинарники, а не собирать инструмент из исходного кода. В таких случаях go tool не поможет, но остаётся опциональной альтернативой.
В целом, большинство OSS-проектов и внутренних тулов будут только «за» принятие новой парадигмы, потому что сборка через go tool упрощает жизнь и авторам, и конечным пользователям.
Личный взгляд: к чему всё идёт
Будучи энтузиастом Go, я часто вижу, как сообщество ищет способы упростить процесс генерации кода, тестирования и деплоя, не жертвуя быстродействием. Для меня go tool — это логичное развитие идеи «инструментального» подхода к Go, который раньше частично реализовывали через tools.go. Мне кажется, что:
🌱 Экосистема будет расти более организованно: инструменты станут чётко разделяться на «рабочие зависимости» (runtime) и «утилиты» (tool).
🏗 Новые библиотеки получат «чистые» go.mod без лишних зависимостей, потому что мы не тянем за собой все парсеры и генераторы кода в продакшн.
🤝 Сообщество сделает шаг к единому стандарту: инструменты больше не будут реализовывать десятки вариантов «запуск через make», «запуск через tools.go», «запуск через отдельные скрипты».
При этом есть нюанс: не все захотят или смогут перейти на Go 1.24 сразу. В больших компаниях с жёсткой политикой версий может пройти время, прежде чем эта функция станет доступна. Но я уверен, что рано или поздно мы увидим массовый переход на новую механику.
Итоги
Go 1.24 открывает перед нами очередную веху эволюции языка. Команда go tool и директива tool в go.mod позволяют:
✅ Подключать необходимые инструменты без захламления основного модуля.
⚙️ Автоматизировать генерацию, тестирование и другие процессы более гибко.
⏱ Существенно ускорять повторные запуски за счёт кэширования.
Для всех, кто всерьёз занимается Go, — это, пожалуй, одни из самых значимых улучшений за последние годы. Да, могут возникнуть мелкие шероховатости, особенно на ранних этапах, но потенциал экономии времени и упрощения процессов разработки несомненен. Если вы ещё не пробовали, очень рекомендую оценить новую возможность «в бою»: даже локально она заметно улучшит ваш повседневный рабочий цикл, а уж в контексте CI/CD — и подавно.
Ссылки на новость и упомянутые ресурсы
- Проект golangci-lint (пример инструмента, который чаще рекомендуют ставить бинарником):
https://github.com/golangci/golangci-lint
Если вы ищете способ сделать свою разработку на Go проще, быстрее и «чище» с точки зрения зависимостей, то Go 1.24 и новая команда go tool — определённо то, что стоит попробовать уже сегодня!