A usina e as tomadas
A usina que gera energia não sabe nada sobre os aparelhos que vão consumi-la — nem a marca, nem o modelo, nem se é um liquidificador ou um notebook. Ela expõe um padrão (a tomada), e cada aparelho se adapta a ele. Trocar o liquidificador por outro não muda nada na usina. Clean Architecture põe as regras de negócio na posição da usina: elas não conhecem o banco, o framework nem a tela — expõem contratos, e os detalhes se pluga nelas. Você troca o 'aparelho' (o banco, a UI) sem tocar na 'usina' (o domínio).
A única regra que importa
As camadas (entidades no centro, depois casos de uso, depois adaptadores, depois frameworks) são famosas pelo diagrama, mas o coração é uma frase: as dependências de código só apontam para dentro. Uma camada externa pode conhecer uma interna; a interna nunca conhece a externa.
O teste prático é brutal e simples: procure no domínio um import de Express, Prisma, React. Se existir, a regra foi violada. O núcleo tem que ser escrito como se banco e framework não existissem — porque, para ele, não existem.
O mecanismo que faz isso funcionar nas fronteiras é a inversão de dependência. O caso de uso precisa persistir um pedido, mas não pode importar o banco (isso apontaria para fora). Então ele define a interface RepoPedidos — que pertence ao anel de dentro — e o adaptador de banco, no anel de fora, a implementa. A dependência de código passa a apontar de fora para dentro (o banco depende da interface do domínio), enquanto o fluxo de execução em tempo real vai de dentro para fora. Essa separação entre direção da dependência e direção da chamada é o truque central.
Vale situar Clean Architecture entre os primos: ela é a síntese da Hexagonal (portas e adaptadores) e da Onion, todas girando em torno da mesma regra de dependência — a diferença é mais de vocabulário e de número de anéis que de essência. E vale o aviso honesto: o custo é real. Cada fronteira invertida é uma interface a mais, e mapear entre a entidade de domínio e o DTO de cada borda gera mappers que não fazem 'nada' visível. Num sistema com regra de negócio rica, isso se paga em testabilidade e longevidade; num CRUD que só lê e grava formulários, é cerimônia pura — e o certo ali é uma arquitetura mais rasa.
Como isso aparece na prática
O núcleo testável sem subir nada
Cenário
Um sistema de precificação tinha regras complexas, mas testá-las exigia subir banco, filas e o framework web inteiro. Os testes eram lentos, frágeis e raramente rodados, e a lógica de preço vivia quebrando em produção.
Como o padrão entra
As regras foram movidas para o centro, com o banco e as filas atrás de interfaces implementadas nas bordas. Os testes do núcleo passaram a rodar com repositórios em memória, sem infraestrutura.
Trade-off: Surgiram interfaces e mappers entre as camadas, e o código ficou maior. Em troca, a lógica de preço passou a ter testes rápidos e confiáveis, e os bugs de negócio caíram.
A Clean Architecture que afogou um CRUD
Cenário
Um time aplicou Clean Architecture completa a um app que era essencialmente formulários lendo e gravando no banco. Cada tela nova exigia entidade, caso de uso, interface de repositório, DTO e três mappers — para praticamente nenhuma regra.
Como o padrão entra
A arquitetura foi achatada: o acesso a dados passou a ser mais direto, mantendo uma separação leve, sem a cerimônia completa de anéis e inversões onde não havia regra de negócio a proteger.
Trade-off: Perdeu-se o isolamento total do domínio. Foi a escolha certa: não havia domínio rico para isolar, e a cerimônia estava custando velocidade sem entregar proteção.
Onde isto dá errado
O framework vazando para o centro
Uma entidade que importa o ORM, ou um caso de uso que recebe o objeto de request do Express, quebra a regra da dependência. O núcleo tem que ser escrito sem conhecer as ferramentas — um único import de framework no domínio já denuncia a violação.
Aplicar a arquitetura inteira num CRUD
Quando não há regra de negócio rica, as camadas, interfaces e mappers viram cerimônia pura: muito código que não protege nada. Clean Architecture se paga em domínios complexos, não em formulários.
Confundir camadas com pastas
Criar pastas 'domain', 'application' e 'infra' sem impor a direção da dependência é teatro. O que vale é a regra — dentro não conhece fora — verificável por lint de dependência, não a organização visual.
Dependência invertida na fronteira
// A REGRA DA DEPENDENCIA: o codigo-fonte so aponta para DENTRO.
// Fora -> dentro. O dominio no centro nao conhece banco nem framework.
//
// [ frameworks/db/web ] -> [ casos de uso ] -> [ entidades ]
// (detalhe) (aplicacao) (dominio)
// dependencia aponta ---------------------------------> para dentro
// O caso de uso depende de uma INTERFACE, definida por ele:
interface RepoPedidos { // <- porta, no anel de aplicacao
salvar(p: Pedido): Promise<void>;
}
class FinalizarPedido { // caso de uso, no centro
constructor(private repo: RepoPedidos) {} // depende da abstracao
async executar(p: Pedido) { await this.repo.salvar(p); }
}
// O detalhe (Prisma, Postgres) IMPLEMENTA a interface, na borda:
class RepoPedidosPrisma implements RepoPedidos { /* ... */ }
// A dependencia foi INVERTIDA: o banco depende do dominio, nao o contrario.
// Por isso o dominio nao tem um unico import de framework.Quando usar × quando evitar
Use quando
3- Em sistemas com regra de negócio rica que precisa sobreviver a trocas de ferramenta.
- Quando testar o núcleo sem infraestrutura é um objetivo real.
- Quando o acoplamento da lógica às ferramentas já se mostrou caro.
Evite quando
2- Em apps pequenos e sobretudo CRUD.
- Quando a cerimônia supera a regra de negócio a proteger.
Testar o que ficou
3 armadilhas de Clean Architecture viram perguntas, com o nome do padrão escondido, misturadas com padrões parecidos.
Onde isto aparece de verdade
Você já usa isto, talvez sem saber o nome.
a regra da dependênciaDependências só apontam para dentro, das camadas externas para as internas; o domínio no centro não conhece banco nem framework.domínio sem import de frameworkO código de negócio que não importa Express, Prisma ou React é o teste prático da Clean Architecture funcionando de verdade.casos de uso no centroA camada de casos de uso orquestra o domínio e é chamada pelas bordas, sem depender de nenhuma delas.
O padrão em uma linha
Sem nome de domínio, sem cerimônia. Só a ideia.
// Dependências apontam para o domínio.
class CriarPedido { constructor(private repo: PedidoRepo) {} }O que ele cobra
2 saltos a mais entre a chamada e o efeito.
- Camadas e inversões de dependência a mais, com mapeamentos entre elas para o domínio não vazar
- Muita cerimônia (interfaces, DTOs, mappers) que não se paga num sistema pequeno
Não vale se: o app é pequeno, é sobretudo CRUD e não tem regra de negócio rica — as camadas só adicionam indireção sem proteger nada.
Costuma ser confundido com
Onde isto aparece
Continue por aqui
- Arquitetura HexagonalIsola o domínio no centro e o conecta ao mundo externo por portas (interfaces) e adaptadores (implementações), tornando infraestrutura um detalhe plugável.
- DIP — Inversão de DependênciaMódulos de alto nível não devem depender de módulos de baixo nível; ambos devem depender de abstrações — e a abstração pertence a quem a usa, não a quem a implementa.
- OCP — Aberto/FechadoMódulos devem ser abertos para extensão e fechados para modificação: adicionar comportamento novo deveria significar escrever código novo, não reabrir e alterar o que já funciona.