Dependency Injection (DI) — передача зависимостей снаружи, а не создание их внутри. В Go это делается через интерфейсы в конструкторе.
type UserService struct {
repo UserRepository // интерфейс, не конкретный тип
mailer EmailSender
}
func NewUserService(repo UserRepository, mailer EmailSender) *UserService {
return &UserService{repo: repo, mailer: mailer}
}
В тестах подставляешь мок, в проде — реальную реализацию. Никаких DI-фреймворков типа Spring обычно не нужно — в Go DI делается руками в main() или через wire (кодогенерация). Чем проще, тем лучше. Главное правило: зависи от интерфейсов, а не от реализаций.