Aula 06 · 50–65 minutos

Escolha com critério

Sexta aula: escolha quando aplicar inversão de dependência em Go.

Resultado e mapa da aula

Esta conclusão transforma o padrão em decisão de engenharia. Você poderá apresentar uma evidência para criar ou recusar uma interface, explicar seu custo e registrar o limite da decisão para que uma futura mudança seja mais simples.

  1. Localize a política e a colaboração.
  2. Verifique se existe variação ou teste relevante.
  3. Compare contrato mínimo e concreto simples.
  4. Defenda o trade-off em revisão e entrevista.

O critério é uma necessidade, não uma estética

Interfaces são úteis quando um consumidor tem uma colaboração clara e você quer testar ou trocar o detalhe. Elas custam leitura, nomes e mais pontos de navegação. Sem um motivo concreto, esse custo não compra flexibilidade útil.

Decisão sobre criar interface
necessidade do consumidor? → variação ou teste relevante? → interface pequena; caso contrário → tipo concreto

Faça três perguntas

  1. Há uma regra de negócio? Se não há política a proteger, talvez seja apenas uma chamada local simples.
  2. O consumidor precisa de poucos comportamentos? Se sim, ele pode possuir um contrato mínimo.
  3. Há uma variação real? Banco, API externa, relógio ou teste determinístico podem justificá-la.

Uma resposta "não" não é fracasso de design. Em Go, começar com o tipo concreto e extrair a interface no consumidor quando o uso aparece costuma ser a opção mais clara.

Trade-offs em linguagem de conversa técnica

Esse argumento descreve fluxo, responsabilidade e alternativa de teste sem prometer abstração para mudanças imaginárias.

Recupere da memória

Qual evidência justifica criar uma interface em Go?

Fonte primária recomendada

Effective Go — Interfaces. Compare interfaces pequenas e concretas como io.Writer com as necessidades do seu caso.

Concluiu a trilha: volte ao índice e use o glossário durante uma refatoração real.

Uma abstração deve pagar seu próprio custo

Problema em trabalho real: Uma interface para cada struct cria mais nomes, indireção e superfície pública, mas não remove acoplamento se não houver um consumidor, uma borda ou uma variação real. A estética de “tudo abstraído” substitui evidência por suposição.

Fluxo e momento de execução: Comece pela política: há uma regra a proteger? Observe a colaboração que ela usa e a variação que precisa controlar. Se ambas são reais, declare o menor contrato no consumidor; se não são, mantenha o concreto e extraia depois, orientado pelo uso.

Abordagem insuficiente: Não crie interfaces antecipadas para “mockar qualquer coisa”. Um tipo concreto simples é a opção mais clara quando não há limite externo, comportamento alternativo ou teste determinístico que precise ser injetado.

Decisão recomendada: Defenda o contrato com a evidência concreta: checkout precisa salvar, PostgreSQL é uma borda e um fake permite provar a regra. Diga também o custo: mais uma API e indireção. Essa honestidade é parte de uma boa decisão de design.

Como verificar na prática: Para cada interface candidata, responda por escrito: qual consumidor a usa, quais métodos ele chama, qual detalhe varia e qual teste ficaria impossível ou caro sem ela? Se não houver resposta específica, não extraia ainda.

Limite de segurança: Não use uma interface como argumento de segurança por si só. Autorização, validação, limite de taxa e proteção de segredos são requisitos explícitos que devem ser testados na camada responsável.

Fonte primária: Effective Go — Interfaces.

Guia de solução do exercício

Fluxo de execução: Identifique uma regra, a colaboração que ela consome e a variação real. Só então decida entre interface pequena ou tipo concreto.

Abordagem inadequada: Criar uma interface antes de qualquer consumidor por “padronização” é abstração prematura.

type Clock interface { Now() time.Time }
// criada sem teste, troca ou consumidor que justifique o contrato

Por que falha e como corrigir: Você adiciona nomes e indireção, mas não remove um acoplamento real. A equipe passa a manter contratos especulativos e mocks sem uma decisão de negócio associada.

Abordagem correta: Extraia a interface no consumidor quando houver variação concreta, como um fake determinístico ou uma borda externa.

type OrderSaver interface { Save(Order) error }
// checkout usa; Postgres e fake satisfazem

Raciocínio, trade-offs e limites: Use tipo concreto para colaboração interna estável e simples. Use interface para uma borda ou quando o teste precisa controlar a colaboração. Explique o trade-off: o ganho é testabilidade e troca localizada; o custo é indireção e mais uma API a manter.

Abra o diagrama relacionado e compare o fluxo.

Pergunta de mercado e entrevista

1. Quando você não criaria uma interface?

Como responder: Quando não há consumidor, variação ou necessidade de teste. Um tipo concreto simples e estável é mais claro.

2. Qual trade-off você explicaria ao revisor?

Como responder: O ganho é testabilidade e troca localizada; o custo é indireção e mais uma API para manter. A decisão deve apontar o acoplamento real que está sendo removido.

3. Interfaces são só para mocks?

Como responder: Não. Elas modelam colaboração entre política e detalhe. Um fake de teste é uma consequência útil, mas não deve ser a única razão para abstrair prematuramente.

Pratique mais 9 questões de recuperação

Responda sem consultar a aula. O feedback é imediato; volte ao trecho relevante antes de tentar de novo.

DI entrega uma dependência; DIP define:

Em Go, uma interface é satisfeita quando:

Quem deve possuir uma interface pequena?

Onde a implementação concreta é escolhida?

Para testar uma regra sem banco, injete:

Uma interface deve conter:

O detalhe PostgreSQL deve depender de:

Qual sinal pede uma interface?

Após a refatoração, a regra não deve importar: