Glossário — Clean Architecture com Go
Termos usados nas lições de Clean Architecture com Go, na ordem em que aparecem. Cresce a cada lição nova.
Clean Architecture
Estilo de arquitetura de software proposto por Robert C. Martin (Uncle Bob) em que o código é organizado em camadas concêntricas, e as regras de negócio ficam isoladas de detalhes técnicos (banco de dados, frameworks, UI). O objetivo é um sistema testável e fácil de mudar, porque os detalhes dependem das regras de negócio — nunca o contrário.
Fonte: The Clean Architecture, Robert C. Martin (2012).
Injeção de Dependência (Dependency Injection)
Técnica em que uma função ou tipo recebe suas dependências prontas de fora (por parâmetro ou construtor), em vez de criá-las internamente. Termo cunhado por Martin Fowler em 2004. É o mecanismo concreto que torna o Dependency Inversion Principle possível na prática — sem DI, não há como uma implementação externa "entrar" numa peça de código que segue a Regra de Dependência.
Fonte: Inversion of Control Containers and the Dependency Injection pattern, Martin Fowler (2004).
Regra de Dependência (Dependency Rule)
O princípio central da Clean Architecture: dependências de código-fonte só podem apontar para dentro, em direção às políticas de mais alto nível. Nada em um círculo interno pode saber algo sobre um círculo externo — nem o nome de uma função, tipo, ou qualquer detalhe de uma camada mais externa. É o Dependency Inversion Principle aplicado sistematicamente a um projeto inteiro, camada por camada.
Dependency Inversion Principle — DIP (Inversão de Dependência)
O "D" do SOLID. Princípio sobre a direção da dependência entre módulos, com duas partes: (1) módulos de alto nível não devem depender de módulos de baixo nível — ambos devem depender de abstrações; (2) abstrações não devem depender de detalhes — detalhes devem depender de abstrações. Diferente de Injeção de Dependência (a técnica): DIP é o princípio — quem deveria depender de quem; DI é o mecanismo — como a implementação chega até quem precisa dela.
Fonte: Design Principles and Design Patterns, Robert C. Martin (2000) — mesmo autor de "The Clean Architecture". O acrônimo SOLID foi cunhado depois, por Michael Feathers.
Entities (Entidades / Domínio)
A camada mais interna. Contém as regras de negócio mais gerais e estáveis do sistema — o que a empresa faria independente de ter software ou não. Não sabe nada sobre banco de dados, HTTP, ou qualquer framework.
Use Cases (Casos de Uso / Aplicação)
Orquestram o fluxo de dados entre as entidades para realizar uma tarefa específica do sistema (ex: "aprovar um pedido"). Contêm as regras de negócio específicas da aplicação, mas ainda não sabem como os dados chegam ou para onde vão.
Interface Adapters
Convertem dados entre o formato mais conveniente para os use cases/entities e o formato mais conveniente para agentes externos (banco de dados, web, etc.). Exemplos: controllers, presenters, gateways.
Frameworks & Drivers
A camada mais externa: banco de dados, framework web, ferramentas de UI. É onde ficam os detalhes técnicos — a camada mais fácil de trocar, porque nada de dentro depende dela.
Hexagonal Architecture (Ports & Adapters)
Arquitetura publicada por Alistair Cockburn em 2005 — anterior à Clean Architecture e citada como uma de suas influências. A ideia central é a mesma: a aplicação (o "hexágono") não conhece o mundo externo diretamente, só através de portas (interfaces que ela define) e adapters (implementações concretas plugadas nessas portas) — o mesmo papel que os Interface Adapters cumprem na Clean Architecture. É o nome mais usado no mercado para esse mesmo conjunto de ideias.
Fonte: Hexagonal Architecture, Alistair Cockburn (2005).
Struct
Tipo concreto em Go que agrupa dados: uma lista de campos nomeados, cada um com um tipo. Não tem comportamento próprio até que métodos sejam declarados para ela. Análogo a uma classe só com atributos, ou a um record/"data class" de outras linguagens.
Interface (Go)
Tipo em Go que agrupa comportamento: uma lista de assinaturas de métodos, sem nenhum dado próprio. Um contrato — o mesmo conceito de interface de outras linguagens orientadas a objetos, com uma diferença: em Go, ela é satisfeita por satisfação implícita, não por declaração explícita.
Satisfação implícita (Implicit Interface Satisfaction)
Mecanismo de Go em que um tipo satisfaz uma interface apenas por ter os métodos que ela exige, sem nenhuma declaração explícita (não existe palavra-chave implements). O compilador confere a satisfação estruturalmente, no ponto de uso. Isso permite que o pacote que implementa uma interface nem precise importar o pacote que a declara. Convenção associada: em Go, a interface deveria ser declarada no pacote que a usa, não no pacote que a implementa — é a Regra de Dependência expressa em pacotes.
Fonte: The Go Programming Language Specification — Interface types; Go Code Review Comments.
Módulo (Go module)
Unidade de versionamento e distribuição de código em Go — na prática, o projeto inteiro. Declarado por um único arquivo go.mod na raiz, que fixa o caminho canônico de importação (module path) e a versão mínima de Go exigida. Análogo ao package.json (Node) ou ao composer.json (PHP), com uma diferença: em Go, esse caminho também funciona como prefixo de import para todo pacote do módulo.
Fonte: Go Modules: Package and Module Layout.
Pacote (Go package)
Unidade de organização de código dentro de um módulo: cada diretório com arquivos .go é um pacote, e todo arquivo nesse diretório compartilha o mesmo package declarado no topo. Um módulo normalmente contém múltiplos pacotes — um por diretório —, mas um pacote nunca atravessa módulos. O caminho de import (module path + caminho da pasta) é o que fisicamente restringe o que um pacote pode acessar de outro: sem a linha de import, não há acesso possível. É a base física da Regra de Dependência em projetos Go.
Fonte: Go Modules: Package and Module Layout.
internal (diretório especial)
Convenção reforçada pelo próprio compilador do Go: qualquer pacote dentro de uma pasta chamada internal só pode ser importado por código do mesmo módulo, a partir do diretório pai de internal. Usado para impedir que outros módulos dependam de pacotes que o projeto não quer expor como API pública — mesmo em repositórios públicos. Não é uma camada da Clean Architecture; é um mecanismo de visibilidade do Go, ortogonal às camadas.
Fonte: Go Modules: Package and Module Layout.
Screaming Architecture
Ideia de Robert C. Martin: a estrutura de pastas de nível mais alto de um sistema deveria comunicar o domínio de negócio que ele resolve, não os frameworks ou bibliotecas usados para construí-lo. Duas afirmações distintas: (1) nomes de pacote nunca deveriam citar uma tecnologia específica (regra rígida); (2) o negócio deveria ser identificável em algum nível visível — módulo, pacote ou arquivo (admite mais de uma solução válida). O teste prático associado: uma regra de negócio deveria ser testável sem nenhum framework presente.
Fonte: Screaming Architecture, Robert C. Martin (Clean Coder Blog, 2011).
Package by Layer (organização por camada)
Forma de organizar pacotes Go em que cada pacote representa um papel arquitetural (domain, usecase, memoria) e cresce horizontalmente conforme o sistema ganha novos casos de uso — um caso de uso novo normalmente vira um arquivo novo dentro de um pacote existente, não um pacote novo. É a organização usada pelo aprovador-pedidos neste curso. Favorece projetos pequenos a médios, com regras de domínio compartilhadas entre vários casos de uso.
Package by Feature (organização por funcionalidade)
Alternativa a Package by Layer: cada caso de uso ou funcionalidade ganha seu próprio pacote, contendo tudo que precisa (domínio, orquestração, implementação). Favorece sistemas grandes com múltiplos times, porque reduz conflito de merge entre times que trabalham em features diferentes; tem o custo de duplicar ou compartilhar regras de domínio entre pacotes de feature. Nenhuma das duas formas viola Screaming Architecture — ambas evitam nomear pacotes por tecnologia.
Making Illegal States Unrepresentable (Estados Impossíveis Irrepresentáveis)
Princípio de design de tipos: em vez de validar um estado inválido depois que ele já foi construído, o tipo de dado é desenhado de forma que o estado inválido nunca possa ser construído. Diferente de validação em runtime — que exige lembrar de checar em todo lugar que o dado é criado ou lido — tornar um estado irrepresentável elimina a necessidade da checagem, porque o caso inválido não é um valor possível do tipo. Neste curso, aplicado ao trocar dois bool independentes (que permitiam Aprovado=true e Rejeitado=true ao mesmo tempo) por um único StatusPedido enumerado.
Fonte: Designing with types: Making illegal states unrepresentable, Scott Wlaschin, citando Yaron Minsky, Effective ML.
iota
Identificador pré-declarado do Go, usado dentro de um bloco const: representa um contador que começa em 0 e incrementa a cada linha do bloco. É o mecanismo idiomático para declarar um conjunto de constantes relacionadas (um "enum", embora Go não tenha esse tipo nativamente) sobre um tipo nomeado, como StatusPedido.
Fonte: The Go Programming Language Specification — Iota.
Valor zero (zero value)
O valor que uma variável de um tipo recebe automaticamente quando é declarada sem inicialização explícita — 0 para tipos numéricos, "" para string, false para bool, e o valor da primeira constante iota de um tipo nomeado sobre um desses. Um dos Go Proverbs de Rob Pike — "Make the zero value useful" — recomenda desenhar tipos de forma que esse valor automático já seja um estado seguro e correto, não um estado que precisa ser corrigido depois.
Fonte: Go Proverbs, Rob Pike (Gopherfest SV 2015).
Pointer receiver vs. value receiver
Em Go, um método pode receber o tipo por valor (func (p Pedido) Metodo(), opera numa cópia) ou por ponteiro (func (p *Pedido) Metodo(), opera no valor original e pode alterá-lo). Métodos que mutam o receiver exigem pointer receiver — um value receiver só alteraria uma cópia descartada ao final do método. A convenção oficial de Go recomenda não misturar os dois estilos no mesmo tipo: se qualquer método precisa de pointer receiver, todos os métodos daquele tipo deveriam usá-lo, por consistência.
Fonte: Effective Go — Pointers vs. Values; Go Code Review Comments — Receiver Type.
Domain Event
Representação de um fato de negócio significativo como um valor de primeira classe, no exato momento em que ele acontece — em vez de deixar esse fato implícito numa mudança de estado que desaparece assim que é sobrescrita. Não exige mensageria, fila ou publicação distribuída; o padrão em si é só sobre nomear o fato como um tipo de dado. Neste curso, PedidoAprovado e PedidoRejeitado nascem dentro de domain, no mesmo método que decide a regra de negócio correspondente.
Fonte: Domain Event, Martin Fowler.
Composition Root
Termo usado na literatura de Injeção de Dependência para o único ponto de um sistema onde as implementações concretas são criadas e entregues aos consumidores que dependem só de interfaces. Neste curso, main.go é o Composition Root — o único arquivo que conhece domain, usecase e memoria ao mesmo tempo, e o primeiro lugar que observa um Domain Event depois que ele é produzido.
Interface fechada (sealed interface)
Padrão em que uma interface declara um método não exportado (nome iniciando com letra minúscula), o que restringe quais tipos podem satisfazê-la a só os declarados dentro do mesmo pacote — nenhum código externo consegue implementar um método que não pode nem ver. Usado para representar "um valor que só pode ser um destes tipos específicos", quando Go não tem um tipo de união nativo. É a mesma técnica usada pelo pacote go/ast da biblioteca padrão, na interface Expr.
Fonte: go/ast — Expr.
Type switch
Construção de Go (switch v := x.(type)) que verifica, em tempo de execução, qual é o tipo concreto guardado dentro de um valor de interface, executando o case correspondente a esse tipo. Usado neste curso para distinguir, em main.go, qual Domain Event concreto (PedidoAprovado ou PedidoRequerRevisaoManual) uma interface fechada como EventoAprovacao está carregando.
Fonte: The Go Programming Language Specification — Type switches.
Interface Segregation Principle — ISP (Segregação de Interfaces)
O "I" do SOLID: clientes não deveriam ser forçados a depender de métodos que não usam. Quando uma interface cresce para acomodar consumidores diferentes, cada consumidor individual passa a depender de métodos que nunca chama — um acoplamento desnecessário. A correção é declarar interfaces pequenas, uma por conjunto real de métodos que um consumidor específico precisa, em vez de uma interface única e genérica reunindo tudo que "parece relacionado". Neste curso, PedidoRepository (Salvar) e PedidoFinder (Buscar) são duas interfaces separadas pelo mesmo motivo.
Fonte: Robert C. Martin, "The Interface Segregation Principle", C++ Report (1996), elaborado em Design Principles and Design Patterns (2000).
Valor sentinela (sentinel error)
Um valor de erro criado uma única vez com errors.New, guardado numa variável de pacote e reutilizado em toda chamada que falha pelo mesmo motivo — em vez de uma nova string de erro a cada chamada. Permite ao chamador comparar o erro recebido com esse valor específico (errors.Is), distinguindo o motivo exato da falha sem depender do texto da mensagem. Aplicação prática do Go Proverb "Errors are values".
Fonte: Go Proverbs, Rob Pike.
Data Transfer Object — DTO
Objeto simples, sem comportamento, desenhado para carregar dados através de uma fronteira — originalmente, entre processos, para reduzir o número de chamadas remotas caras e encapsular o mecanismo de serialização. Neste curso, arquivo.registro (Lição 4) é um DTO no sentido estrito, motivado por uma fronteira real de serialização (arquivo JSON). Fowler também alerta, em LocalDTO, que criar DTOs sem uma fronteira remota real — só "para desacoplar" uma chamada local — costuma custar mais (mapeamento de dados) do que compensa.
Fonte: Data Transfer Object, Martin Fowler; LocalDTO, Martin Fowler.
Input (deste curso)
Struct de entrada de um caso de uso, carregando só os campos que aquele caso de uso específico precisa — sem nenhum campo que permitiria a quem chama declarar uma decisão que só a regra de negócio deveria tomar. Diferente de um DTO no sentido de Fowler: motivado por proteger uma fronteira de responsabilidade dentro do mesmo processo, não por reduzir chamadas remotas ou encapsular serialização. Exemplos: AprovarPedidoInput (ID, Total — sem Status), RejeitarPedidoInput (só ID). Corresponde ao Request Model, na terminologia de Uncle Bob (Lição 10).
Interactor
Termo de Robert C. Martin (Clean Architecture) para o objeto que orquestra a regra de negócio de uma operação específica — o que este curso sempre chamou de caso de uso. Neste projeto: AprovarPedido, RejeitarPedido, ConsultarPedido, cada um com seu método Executar.
Fonte: Robert C. Martin, Clean Architecture: A Craftsman's Guide to Software Structure and Design (2017).
Input Boundary / Input Port
Interface que separa quem inicia uma operação (o Controller) de quem a executa (o Interactor) — o Controller depende só dessa interface, nunca do Interactor concreto. "Input Boundary" é o termo de Robert C. Martin (Clean Architecture); "Input Port" é o termo de Alistair Cockburn (Arquitetura Hexagonal, Lição 5) para o mesmo conceito — linhagens diferentes, mesma ideia. Neste projeto, essa peça ainda não existe: main.go chama os casos de uso pelo tipo concreto, uma escolha válida enquanto ele for o único consumidor (Lição 10).
Fonte: Robert C. Martin, Clean Architecture (2017); Hexagonal Architecture, Alistair Cockburn (2005).
Output Boundary / Output Port
Interface que um Interactor usa para se comunicar para fora — tipicamente persistência. "Output Boundary" (Uncle Bob) e "Output Port" (Cockburn) descrevem o mesmo conceito. Neste projeto: PedidoRepository (Lição 4) e PedidoFinder (Lição 8).
Request Model / Response Model
Na terminologia de Uncle Bob: Request Model é o dado de entrada de um caso de uso, moldado especificamente para a operação; Response Model é o dado de saída. Neste projeto, o Input de cada caso de uso (Lição 9) é o Request Model; o Domain Event que Executar devolve (Lição 7) faz dupla função como Response Model — uma coincidência válida enquanto as duas descrições continuarem representando exatamente a mesma informação (Lição 10).
Controller (Clean Architecture)
Quem inicia uma operação: recebe um comando externo (uma requisição HTTP, um comando de CLI), monta o Request Model, e chama o Interactor através da Input Boundary. Distinto do Composition Root (main.go, Lição 4) — hoje, main.go acumula os dois papéis, porque não existe ainda um comando externo real processado por um handler separado.
Presenter (Clean Architecture)
Quem recebe o Response Model de um Interactor e o transforma no formato que uma interface externa precisa exibir. Este projeto ainda não tem um — main.go só imprime o Response Model diretamente. A peça aparece formalmente na Lição 18 (Presenters e ViewModels), quando existir uma saída real exigindo formatação específica.
pgx
Driver e toolkit de acesso ao PostgreSQL para Go, mantido em github.com/jackc/pgx. Diferente de database/sql com um driver genérico, pgx expõe funcionalidades específicas do Postgres diretamente, em troca de abrir mão da portabilidade entre bancos relacionais diferentes. É o driver Postgres mais usado e mantido no ecossistema Go atual. Neste curso, usado via o subpacote pgxpool, que gerencia um pool de conexões seguro para uso concorrente.
Fonte: pgx — documentação oficial (pkg.go.dev); jackc/pgx (GitHub).
Upsert (ON CONFLICT DO UPDATE)
Cláusula padrão de SQL do Postgres (não específica de nenhum driver): insere uma linha nova se a chave já não existir, ou atualiza a linha existente se existir — uma única operação para os dois casos. Neste curso, usada em postgres.PedidoRepository.Salvar, permitindo que a interface PedidoRepository mantenha um único método Salvar, sem exigir que cada caso de uso saiba se está criando ou atualizando um Pedido.
Valor sentinela traduzido entre camadas
Padrão em que um erro específico de uma biblioteca externa (como pgx.ErrNoRows) é convertido, dentro do adapter que a usa, para o mesmo valor sentinela já definido para aquela situação (como ErrPedidoNaoEncontrado, desde a Lição 8) — garantindo que o pacote usecase nunca precise importar ou conhecer os erros específicos de uma biblioteca de infraestrutura, mesmo trocando de implementação (memória, Postgres, ou qualquer outra) por baixo da mesma interface.