Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Dependency Injection in Go

Dependency Injection in Go

Reduza a complexidade e aumente a capacidade de reutilização dos seus módulos em Go através de baixo acoplamento, menos código e testes de unidade mais fáceis.

Avatar for Tiago Angelo

Tiago Angelo

November 25, 2019
Tweet

More Decks by Tiago Angelo

Other Decks in Programming

Transcript

  1. O que é Injeção de dependência? 01 Por quê? Containers

    de Injeção de Dependências Alternativas para Go Wire Let’s Code! 02 03 04 05 06
  2. { 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
  3. { 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 { … }
  4. 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.
  5. 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.
  6. 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.
  7. Frameworks para Go 04. ALTERNATIVAS PARA GO • Uber's Dig

    • Facebook's Inject • Google's Wire
  8. 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.
  9. 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 { ... }
  10. 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 }
  11. 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)), )
  12. 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{} }
  13. 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