Dependency Injection контейнер для Go (Golang): Wire, Dig и Uber FX

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

Dependency Injection контейнер для Go (Golang): Wire, Dig и Uber FX

Dependency Injection (DI) — это паттерн проектирования, при котором объект получает свои зависимости извне, а не создаёт их сам. В Go (Golang) DI особенно полезен для создания модульного, тестируемого и масштабируемого кода. Наиболее популярные инструменты DI для Go — это Google Wire, Uber Dig и Uber FX. В этой статье мы рассмотрим каждый из них, их особенности и примеры использования.

Зачем нужен Dependency Injection в Go?

Go — статически типизированный язык с явной передачей параметров. Без DI разработчики часто создают глобальные переменные или фабрики, что усложняет тестирование и поддержку. DI контейнеры решают эти проблемы:

  • Слабая связанность — компоненты зависят от интерфейсов, а не от конкретных реализаций.
  • Тестируемость — легко подменять зависимости на моки.
  • Упрощение конфигурации — контейнер автоматически разрешает граф зависимостей.

Google Wire — генерация кода во время компиляции

Wire от Google — это не runtime-контейнер, а генератор кода. Он анализирует функции-конструкторы и генерирует код для связывания зависимостей на этапе компиляции. Это даёт нулевую нагрузку во время выполнения и раннее обнаружение ошибок.

Установка Wire

go install github.com/google/wire/cmd/wire@latest

Пример использования Wire

Предположим, у нас есть сервис, который зависит от базы данных и логгера:

// main.go
package main

import "fmt"

type Logger struct{}

func NewLogger() Logger { return Logger{} }

func (l Logger) Log(msg string) { fmt.Println(msg) }

type Database struct {
    logger Logger
}

func NewDatabase(logger Logger) Database {
    return Database{logger: logger}
}

type Service struct {
    db  Database
    log Logger
}

func NewService(db Database, log Logger) Service {
    return Service{db: db, log: log}
}

Теперь создадим файл wire.go с инструкцией для Wire:

// wire.go
//go:build wireinject
// +build wireinject

package main

import "github.com/google/wire"

func InitializeService() Service {
    wire.Build(NewLogger, NewDatabase, NewService)
    return Service{}
}

Запустим генерацию:

wire

Wire создаст файл wire_gen.go с готовым кодом инициализации:

// wire_gen.go
// Code generated by Wire. DO NOT EDIT.

package main

func InitializeService() Service {
    logger := NewLogger()
    database := NewDatabase(logger)
    service := NewService(database, logger)
    return service
}

Плюсы Wire:

  • Ошибки на этапе компиляции.
  • Нет reflection, высокая производительность.
  • Простой и предсказуемый код.

Минусы Wire:

  • Требует отдельного шага генерации.
  • Сложно использовать с динамическими зависимостями.

Uber Dig — runtime-контейнер с reflection

Dig от Uber — это контейнер, работающий во время выполнения. Он использует reflection для анализа типов и автоматического разрешения зависимостей. Dig предоставляет простой API для регистрации конструкторов и извлечения объектов.

Установка Dig

go get go.uber.org/dig

Пример использования Dig

package main

import (
    "fmt"
    "go.uber.org/dig"
)

type Config struct {
    Port int
}

func NewConfig() *Config {
    return &Config{Port: 8080}
}

type Server struct {
    config *Config
}

func NewServer(c *Config) *Server {
    return &Server{config: c}
}

func (s *Server) Start() {
    fmt.Printf("Server started on port %d\n", s.config.Port)
}

func main() {
    container := dig.New()

    // Регистрируем конструкторы
    container.Provide(NewConfig)
    container.Provide(NewServer)

    // Извлекаем и запускаем сервер
    container.Invoke(func(s *Server) {
        s.Start()
    })
}

Плюсы Dig:

  • Простой и интуитивный API.
  • Поддержка групп зависимостей (например, несколько реализаций интерфейса).
  • Работает в runtime, не требует генерации.

Минусы Dig:

  • Использует reflection, что может снизить производительность.
  • Ошибки проявляются только во время выполнения.

Uber FX — фреймворк для прилож

Рекомендаций