Inversão de Controle

Inversão de Controle, ou IoC, é aquela coisa que promete fazer sua vida de programador muito mais fácil. A ideia é parar de encher seu código de dependências e começar a separar o que fazer do como fazer.

O que é

Basicamente, Inversão de Controle significa que quem manda no seu código é você, ao invés de seguir um passo a passo fixo. Você mantém sua área de trabalho limpa e separa o que precisa ser feito do como fazer. A promessa é que seus testes sejam tranquilos e que seu código continue funcionando mesmo depois daquele super update.

Por que usar?

IoC é como aqueles conselhos que a gente ouve de um parente: não é bom seguir cegamente, mas ajuda mais do que insistir em um código bagunçado. Usar IoC pode economizar tempo na manutenção e passar a impressão de que você tem tudo sob controle para os clientes.

Cenário

No mundo dos computadores, temos um cenário onde o seu código principal, ou domínio, está sempre tentando achar a classe que guarda seus dados.

dependencia

Parece tranquilo, mas o domínio realmente precisa saber todos detalhes da classe repositório? Bastaria ele saber que precisa salvar no banco, sem se preocupar com os detalhes.

Para resolver isso, criamos uma interface que diz como salvar, mas não se importa com quem faz o trabalho.

dependencia-invertendo

O serviço de repositório faz o trabalho de verdade, enquanto o domínio se finge de desentendido.

Benefícios

Seu código fica independente, como um aluno que acabou de ir morar sozinho. Se mudar algo no banco de dados, o domínio não liga. Testes tornam-se fáceis, já que não precisamos ligar um banco de dados gigante só para um pequeno teste.

Da teoria à prática

Imagine um código que manda e-mail e salva dados. Reescrevemos esse código bagunçado em algo que qualquer um deve entender.

1. Código bagunçado

public class PedidosService
{
    public void AnalisarPedido(Pedido pedido)
    {
        if (pedido.Total > 10m)
        {
            pedido.Suspeito();
            this.EnviarEmailAlerta(pedido);
        }

        new PedidoRepositorySql().SalvarPedido(pedido);
    }

    private void EnviarEmailAlerta(Pedido pedido)
    {
        // Código para enviar e-mail
    }
}

2. Aplicando IoC

Veja como fica mais limpo: PedidoService não precisa saber como criar o repositório ou serviço de e-mail, só que deve usá-los.

public class PedidosService
{
    private readonly IPedidoRepository _pedidoRepository;
    private readonly IEmailService _emailService;

    public PedidosService(
        IPedidoRepository pedidoRepository,
        IEmailService emailService)
    {
        _pedidoRepository = pedidoRepository;
        _emailService = emailService;
    }

    public void AnalisarPedido(Pedido pedido)
    {
        if (pedido.Total > 10m)
        {
            pedido.Suspeito();
            _emailService.EnviarEmailAlerta(pedido);
        }

        _pedidoRepository.SalvarPedido(pedido);
    }
}

Para isso rodar, precisamos de classes que façam o que as interfaces pedem.

public interface IEmailService
{
    void EnviarEmailAlerta(Pedido pedido);
}

public interface IPedidoRepository
{
    void SalvarPedido(Pedido pedido);
}

public class PedidoRepositorySql : IPedidoRepository
{
    public void SalvarPedido(Pedido pedido) { }
}

public class EmailGoogleService: IEmailService
{
    public void EnviarEmailAlerta(Pedido pedido) { }
}

Esses códigos podem estar em qualquer lugar, em classes diferentes ou mesmo perdidos por aí. Mas aqui, a flexibilidade é o que importa.

Flexibilidade

PedidoService não sabe qual banco de dados ou serviço de e-mail está usando. Pode ser qualquer um:

// Repositorio Sql, email do Google
var pedidoService = new PedidosService(new PedidoRepositorySql(), new EmailGoogleService());
// Repositorio Oracle, email do Google 
var pedidoService = new PedidosService(new PedidoRepositoryOracle(), new EmailGoogleService());
// Repositorio MySql, email do Google
var pedidoService = new PedidosService(new PedidoRepositoryMySql(), new EmailGoogleService());
// Repositorio Mongo, e-mail chimp
var pedidoService = new PedidosService(new PedidoRepositoryMongoDb(), new MailChimpService());

Tudo isso sem mudar uma linha no serviço. Legal, né?

Conclusão

Falamos sobre IoC, que anda lado a lado com a Injeção de Dependências. Hoje só falamos de IoC, mas logo trago mais sobre DI. Deixe seus comentários e vamos discutir mais sobre isso!