4.5Kпросмотров
99.5%от подписчиков
18 февраля 2026 г.
Score: 5.0K
Wire - Стандарт DI в Go.
В продолжение серии статей для молодого поколения хочу рассказать о том, как менеджерят зависимости на проектах взрослые дяди. До этого поста во всех своих проектах вы, вероятно, просто прокидывали в Init-функции имплементации интерфейсов, и это работало неплохо. Но с ростом проекта это превратится в ад. func main() { config := NewConfig() db := NewDatabase(config) repo := NewUserRepository(db) service := NewUserService(repo) handler := NewHandler(service) // ... и так далее
} Знакомая картина? Чтобы увеличить читаемость и поддерживаемость в go используют инструменты для DI, самый популярный из них от Гугла - Wire, который в основном использовал я. Так же есть Uber Fx / Dig, но они работают на рефлексии и в рантайме, что явно хуже для производительности и наплодит больше ошибок, в отличии от Wire который работает на кодогенерации и определяет типы на момент генерации. Как выглядит Wire под капотом
Неоспоримый плюс Wire, что он не колдует в рантайме. Он просто генерирует обычный Go-код, который вы бы сами написали, если бы не лень. Вы описываете в специальном файле, какие конструкторы (провайдеры) у вас есть, а Wire смотрит на типы аргументов и результаты и собирает из этого граф зависимостей. Если где-то тип не сходится или чего-то не хватает — вы увидите ошибку ещё на этапе go generate, а не после деплоя в два часа ночи. Три кита Wire
1. Провайдеры (Providers) - это обычные функции, которые создают и возвращают объект. Могут возвращать ошибку и даже функцию cleanup (чтобы закрыть соединение, например). Обычные фабрики, если выражаться на паттерновом. 2. Инжекторы (Injectors) - это функции, которые вы объявляете, но не реализуете. Вы пишете только сигнатуру и говорите: "Собери мне всё это хозяйство с помощью набора провайдеров". Wire сам сгенерирует тело функции. Обычно инжекторы живут в файле с названием wire.go и тегом //go:build wireinject, чтобы они не компилировались в обычной сборке. //go:build wireinject func InitializeApp() (*App, error) { wire.Build(NewConfig, NewDB, NewUserRepo, NewHandler, NewApp) return nil, nil
} 3. Наборы провайдеров (Set) - когда провайдеров становится много, удобно группировать их по пакетам с помощью wire.NewSet. Собираете набор в пакете repository, другой в service и потом в инъекторе подключаете оба. var RepoSet = wire.NewSet(NewUserRepo, NewPostRepo) Как это затащить в проект
1. Установить утилиту (один раз): go install github.com/google/wire/cmd/wire@latest 2. Написать провайдеры (скорее всего уже есть - это конструкторы структур) 3. Создать файл wire.go в нужном пакете (обычно в cmd/app или там, где лежит main). Описать инжекторы и сеты 4. Запустить генерацию: wire 5. В main.go просто вызвать сгенерированную функцию: func main() { app, err := InitializeApp() if err != nil { log.Fatal(err) } app.Run()
}