Injeção de dependências e FX
Injeção de dependências (Dependency Injection)
[editar | editar código]Injeção de dependências é um padrão de design que trata da maneira como objetos e seus dependentes são criados e conectados. Em vez de um objeto instanciar diretamente suas dependências, estas são fornecidas (ou "injetadas") por um componente externo, geralmente um framework ou contêiner de injeção.
Este padrão é especialmente útil para grandes aplicações, mas deve-se considerar suas vantagens e desvantagens.
Vantagens
[editar | editar código]- Desacoplamento: facilita a substituição de componentes (muito útil para testes, pois facilita o uso de mocks).
- Melhor organização e legibilidade do código.
- Facilita a manutenção de grandes bases de código.
- Facilita o desenvolvimento concorrente.
Desvantagens
[editar | editar código]- Interfaces que demandam detalhes de configuração.
- Dificulta a depuração ao separar comportamento e construção.
- Encoraja dependência em relação a frameworks.
Frameworks
[editar | editar código]Este tutorial será focado em injeção de dependências em Go utilizando o framework FX. A lista abaixo indica ferramentas que podem ser utilizadas para injeção de dependências em outras linguagens:
- Java: Spring, Guice, Dagger
- Python: dependency-injector, Injector
- C# (.NET): Microsoft.Extensions.DependencyInjection
- JavaScript/TypeScript: InversifyJS
- Ruby: dry-container, Mutant
- C++: Fruit, Boost.DI
- Rust: shaku
- Kotlin: Koin, Dagger (via kapt)
FX: Injeção de Dependências para Go
[editar | editar código]O FX é um framework desenvolvido pela Uber para resolver a complexidade da inicialização e composição de grandes serviços em Go, facilitando a injeção de dependências automática através do uso de construtores e grafos de dependência. É distribuído como software livre sob a licença MIT.
Principais características do FX:
- Usa construtores para declarar dependências.
- Cuida da ordem de inicialização dos componentes.
- Suporta ciclos de vida com hooks (ex:
OnStart,OnStop). - Facilita composição modular (ex:
fx.Provide,fx.Invoke). - Ideal para aplicações grandes e com muitos serviços e módulos.
Mini tutorial de FX (Go)
[editar | editar código]O tutorial abaixo foi elaborado com base no tutorial da JetBrains, mas foi traduzido e generalizado para não depender da IDE GoLand. Para aprofundamento, a documentação oficial do FX apresenta um tutorial mais longo e detalhado na seção Get started.
Pré-requisitos
[editar | editar código]- Caso ainda não tenha instalado, instale o Go: https://go.dev/dl/
- Crie um diretório para seu projeto, e.g.
fxdemo, e inicialize comgo mod init <path>/fxdemo— Atenção: este path não é o path do diretório no seu computador, mas um path que você está definindo para o seu módulo. Geralmente, para módulos públicos (como o FX), esse path é a URL do repositório. Neste exemplo, você pode usar qualquer coisa. Isso vai criar um arquivo go.mod dentro do diretório do seu projeto. - Adicione o FX usando o comando:
go get go.uber.org/fx
Estruturando o projeto
[editar | editar código]
No diretório do seu projeto, crie um arquivo main.go com os componentes necessários:
package main
import "fmt"
type User struct {
name string
}
// NewUser - Cria uma nova instância de User
func NewUser(name string) User {
return User{name: name}
}
// NewUserName - Retorna uma string que fornece um nome para um novo user
func NewUserName() string {
return "Livia"
}
// Get - Um método que tem user como dependência
func (u *User) Get(message string) string {
return fmt.Sprintf("Hello %s - %s", u.name, message)
}
// Run - Depende do user e chama o método Get que estende User
func Run(user User) {
result := user.Get("It's nice to meet you!")
fmt.Println(result)
}
func main() {
// Vamos inserir o código do FX aqui
}
Injetando dependências com o FX
[editar | editar código]
Na sua função main(), forneça as dependências ao FX e invoque a função Run:
func main() {
fx.New(
fx.Provide(
NewUserName,
NewUser,
),
fx.Invoke(Run),
).Run()
}
Não se esqueça de adicionar o FX aos imports:
import (
"fmt"
"go.uber.org/fx"
)
Executando
[editar | editar código]No terminal, execute seu programa com os seguinte comando:
go run main.go
O output esperado é:
[Fx] PROVIDE fx.Lifecycle <= go.uber.org/fx.New.func1()
[Fx] PROVIDE fx.Shutdowner <= go.uber.org/fx.(*App).shutdowner-fm()
[Fx] PROVIDE fx.DotGraph <= go.uber.org/fx.(*App).dotGraph-fm()
[Fx] PROVIDE string <= main.NewUserName()
[Fx] PROVIDE main.User <= main.NewUser()
[Fx] INVOKE main.Run()
[Fx] RUN provide: main.NewUserName() in 25.25µs
[Fx] RUN provide: main.NewUser() in 2.458µs
Hello Livia - It's nice to meet you!
[Fx] RUNNINGTestando
[editar | editar código]
Para testar seu código, crie um arquivo main_test.go no diretório do seu projeto (mesmo nível do main.go). Os testes unitários abaixo usam o pacote testing.
package main
import (
"fmt"
"testing"
)
func TestNewUser(t *testing.T) {
name := "Livia"
expected := User{name: name}
actual := NewUser(name)
if actual != expected {
t.Error("Expected User is not same as actual user")
}
}
func TestUser_Get(t *testing.T) {
name := "Livia"
user := NewUser(name)
message := "Hello there!"
expected := fmt.Sprintf("Hello %s - %s", user.name, message)
actual := user.Get(message)
if actual != expected {
t.Error("Expected User is not same as actual user")
}
}
Referências
[editar | editar código]Sobre injeção de dependências
[editar | editar código]- Martin Fowler, Inversion of Control Containers and the Dependency Injection pattern (2004) — Apesar de antigo, esse artigo foi essencial para formalizar e popularizar o padrão de injeção de dependências
- Robert C. Martin (“Uncle Bob”), The Clean Code Blog: A Little Architecture (2016)
- Wikipedia, Dependency Injection
Sobre o FX
[editar | editar código]- Repositório do FX no GitHub — uber-go/fx: A dependency injection based application framework for Go
Documentação
[editar | editar código]- Documentação oficial — https://uber-go.github.io/fx/
- Documentação no repositório de pacotes Go — https://pkg.go.dev/go.uber.org/fx
Tutoriais
[editar | editar código]- Tutorial oficial do FX — Get started with Fx
- Go with FX — JetBrains Guide
Nota: depois de escrito com base nas referências citadas, este texto foi revisado utilizando o ChatGPT.