O documento discute injeção de dependências em Go. Explica que a injeção de dependências permite baixo acoplamento entre classes ao mover a criação de objetos de dependência para fora da classe. Também discute containers de injeção de dependências como Wire, que ligam abstrações a implementações concretas e injetam dependências nos construtores. O Wire usa um gerador de código para definir providers e construir um injector sem usar reflection.
5. {
SEM INJEÇÃO DE DEPENDÊNCIAS
a struct que
verifica o clima é
responsável por
instanciar o logger
e a que identifica a
localização atual e
01. O QUE É INJEÇÃO DE DEPENDÊNCIA?
// declarações de pacote e importações omitidas
type Weather struct {
log log.Logger
locator location.Locator
}
func NewWeather() *Weather {
log := log.NewZapLogger()
locator := location.NewIPStack()
return &Weather{log: log, locator: locator}
}
func (w *Weather) Check() string {
w.log.Info("Checking the current weather")
local := w.locator.WhereAmI()
return w.CheckByCoord(local.Longitude, local.Latitude)
}
func (w *Weather) CheckByCoord(lat float64, lon float64) string { … }
interfaces
conhece as
implementações
dessas
interfaces
6. {
COM INJEÇÃO DE DEPENDÊNCIAS
o mesmo código
usando DI
01. O QUE É INJEÇÃO DE DEPENDÊNCIA?
// declarações de pacote e importações omitidas
type Weather struct {
log log.Logger
locator location.Locator
}
func NewWeather(log log.Logger, locator location.Locator) *Weather {
return &Weather{log: log, locator: locator}
}
func (w *Weather) Check() string {
w.log.Info("Checking the current weather")
local := w.locator.WhereAmI()
return w.CheckByCoord(local.Longitude, local.Latitude)
}
func (w *Weather) CheckByCoord(lat float64, lon float64) string { … }
7.
8. INVERSÃO DE CONTROLE
02. POR QUÊ?
Por quê?
● garantir o princípio de responsabilidade única.
Como?
● movendo para outras classes quaisquer
responsabilidades adicionais que uma classe
possua, além de sua principal.
9. INJEÇÃO DE DEPENDÊNCIAS
02. POR QUÊ?
Por quê?
● implementar o princípio de inversão de controle;
● obter baixo acoplamento entre as classes.
Como?
● movendo a criação do objeto de dependência
para fora da classe e fornecendo esses objetos
para ela.
10.
11.
12. CONTAINERS DE INJEÇÃO DE DEPENDÊNCIAS
● também conhecidos como Containers de Inversão de Controle (IoC);
● fazem a ligação entre as abstrações e os tipos concretos que a implementam;
● sabe como instanciar as implementações;
● analisam os tipos de cada argumento do construtor e injeta as dependências nele.
15. Frameworks para Go
04. ALTERNATIVAS PARA GO
● Uber's Dig
● Facebook's Inject
● Google's Wire
16.
17. Wire
05. WIRE
● surgiu como parte do projeto Go Cloud;
● inspirado no Dagger 2 de Java;
● roda como um gerador de código e por isso
opera sem uso de reflection;
● código gerado é legível.
18. 1. Instalação
05. WIRE
$ go get github.com/google/wire/cmd/wire
● no diretório da sua aplicação, execute:
19. 2.1. Definindo Providers
05. WIRE
// declarações de pacote e importações omitidas
type Weather struct {
log log.Logger
locator location.Locator
}
func NewWeather(l log.Logger, ll location.Locator) *Weather { // Provider: normalmente são construtores
return &Weather{log: l, locator: ll}
}
func (w *Weather) Check() string {
w.log.Info("Checking the current weather")
local, _ := w.locator.WhereAmI()
return w.CheckByCoord(local.Longitude, local.Latitude)
}
func (w *Weather) CheckByCoord(lat float64, lon float64) string { ... }
20. 2.2. Definindo Providers
05. WIRE
package log
import (
"go.uber.org/zap"
defaultLogger "log"
)
func NewSugaredLogger() *zap.SugaredLogger { // Provider: uma função capaz de produzir um valor
logger, err := zap.NewDevelopment()
if err != nil {
defaultLogger.Fatal(err)
}
log := logger.Sugar()
log.Debug("criando nova instância de SugaredLogger da biblioteca Zap")
return log
}
21. 2.3. Definindo Providers
05. WIRE
package log
import (
"github.com/google/wire"
)
var Providers = wire.NewSet( // Providers podem ser agrupados
NewSugaredLogger,
NewZapLogger,
wire.Bind(new(Logger), new(*ZapLogger)),
)
22. 3. Definindo o Injector
05. WIRE
//+build wireinject - essa tag garante que esse arquivo não seja incluído na build final.
package main
import (
"github.com/angelokurtis/golang-meetup/internal/http"
"github.com/angelokurtis/golang-meetup/internal/log"
"github.com/angelokurtis/golang-meetup/pkg/forecast"
"github.com/angelokurtis/golang-meetup/pkg/location"
"github.com/google/wire"
)
func Initialize() *Weather {
wire.Build(http.Providers, log.Providers, forecast.Providers, location.Providers)
return &Weather{}
}
23. 4. Gerar o Injector
05. WIRE
$ wire
● no diretório da sua aplicação, execute:
o resultado será salvo em um arquivo chamado
wire_gen.go