Введение в управление зависимостями в Go
Почти любой реальный проект использует чужой код: HTTP-роутер, драйвер PostgreSQL, библиотеку для UUID, YAML-парсер, Telegram SDK. Такой внешний код называется зависимостью.
Управление зависимостями отвечает на практические вопросы:
- какие пакеты нужны проекту;
- какие версии этих пакетов используются;
- где их скачать;
- как другой разработчик получит те же версии;
- как удалить то, что больше не используется.
В Go для этого используется система Go Modules.
Модуль
Модуль - это корень Go-проекта с файлом go.mod. Обычно один репозиторий содержит один модуль.
Создать модуль:
go mod init github.com/username/weather-cli
После этого появится go.mod:
module github.com/username/weather-cli go 1.22
module задает module path. Если проект будет опубликован на GitHub, обычно используют путь репозитория. Для учебного локального проекта можно использовать условный путь, но лучше сразу привыкать к реальному формату.
Import path
Пакеты внутри модуля импортируются относительно module path:
github.com/username/weather-cli/internal/config
Если в go.mod написано:
module github.com/username/weather-cli
а пакет лежит в:
internal/config
то import будет:
import "github.com/username/weather-cli/internal/config"
Если module path выбран случайно, импорты тоже станут случайными. Поэтому имя модуля лучше выбирать внимательно.
go.mod
go.mod хранит:
- имя модуля;
- версию Go;
- прямые зависимости;
- иногда indirect dependencies;
- replace directives, если они нужны локально.
Пример:
module github.com/username/books-api go 1.22 require ( github.com/go-chi/chi/v5 v5.0.12 github.com/google/uuid v1.6.0 )
Этот файл нужно коммитить. Без него другой человек не поймет, какие зависимости нужны проекту.
go.sum
go.sum хранит checksums зависимостей. Он помогает Go проверить, что скачанный код совпадает с ожидаемым.
go.sum тоже нужно коммитить. Это не временный файл и не lock-файл в привычном смысле, но он важен для воспроизводимости и безопасности.
Добавление зависимости
Чтобы добавить зависимость:
go get github.com/google/uuid
После этого можно импортировать пакет:
import "github.com/google/uuid" id := uuid.NewString()
Go обновит go.mod и go.sum.
Часто зависимость добавляется автоматически при:
go mod tidy
если импорт уже есть в коде.
Версии
Go Modules используют semantic versioning:
v1.2.3
1- major;2- minor;3- patch.
Patch обычно содержит исправления. Minor добавляет функциональность без ломания совместимости. Major может ломать API.
Для major version v2+ в Go меняется import path:
import "github.com/go-chi/chi/v5"
Это не случайность. Go делает major version частью пути, чтобы разные major versions могли сосуществовать.
Обновление зависимости
Обновить до последней совместимой версии:
go get github.com/google/uuid@latest
Указать конкретную версию:
go get github.com/go-chi/chi/v5@v5.0.12
После обновления запускайте тесты:
go test ./...
Даже minor update может изменить поведение в деталях.
Удаление зависимости
Чтобы удалить зависимость:
- Удалите import из кода.
- Удалите использование пакета.
- Выполните:
go mod tidy
tidy удалит неиспользуемые зависимости из go.mod и go.sum.
go mod tidy
go mod tidy приводит файлы модуля в соответствие с кодом:
- добавляет зависимости, которые импортируются;
- удаляет зависимости, которые больше не нужны;
- обновляет
go.sum.
Эту команду полезно запускать перед commit.
Indirect dependencies
В go.mod можно увидеть:
require github.com/some/package v1.2.3 // indirect
Indirect dependency нужна не вашему коду напрямую, а одной из ваших зависимостей. Обычно не нужно редактировать такие строки руками.
replace
replace позволяет временно заменить модуль локальным путем или другим источником:
replace github.com/example/lib => ../lib
Это удобно для локальной разработки нескольких модулей, но будьте осторожны: случайный replace на путь вроде /Users/alice/lib сломает проект у других людей.
Чеклист
- В корне проекта есть
go.mod. - Module path выбран осознанно.
go.modиgo.sumзакоммичены.- Зависимости добавляются через
go getилиgo mod tidy. - Неиспользуемые зависимости удаляются через
go mod tidy. - После обновления зависимостей запускаются тесты.
replaceне содержит локальных путей перед публикацией.