Dominando a Arquitetura de Clean Architecture
Princípios, camadas e práticas para manter domínio estável, código testável e evolução segura
1. Fundamentos essenciais da Clean Architecture
Ao longo da minha prática, a Clean Architecture voltou-se uma bússola para manter o código sustentável diante de mudanças. O foco é preservar o domínio como núcleo, isolando-o de frameworks, detalhes de infraestrutura e interfaces externas.
- Domínio no centro: entidades e regras de negócio que não devem depender de tecnologias específicas.
- Dependências que fluem inward: camadas externas podem depender de interfaces definidas pelo núcleo, nunca o contrário.
- Separa o que é domínio do que é entrega: define claramente camadas de aplicação, interfaces e infraestrutura.
- Testabilidade elevada: possibilidades de isolar o domínio para testes unitários sem dependências de UI, bancos ou redes.
2. Camadas e responsabilidades
A arquitetura tipicamente organiza-se em camadas concêntricas. Cada camada consome apenas aquelas acima dela que são estáveis e definidas por interfaces. Em termos práticos, as camadas costumam ser:
- Entidades (Domínio): regras de negócio e objetos que representam o modelo de negócio.
- Casos de Uso (Aplicação): coordena fluxos de negócios, orquestra entidades e validações de regras aplicáveis.
- Adaptadores de Interface (Presenters, Controllers, Gateways): traduz entre o domínio e o mundo externo (UI, API, bancos, serviços).
- Frameworks e Drivers (Infraestrutura): bancos de dados, UI, serviços externos, bibliotecas de terceiros.
Regra de dependência destaca que código interno não deve importar detalhes da infraestrutura. Em vez disso, dependemos de interfaces que o mundo externo implementa tarde. Esse acoplamento mínimo facilita substituições, testes e evolução sem quebrar o domínio.
3. Interfaces, boundaries e inversão de dependência
As fronteiras (boundaries) definem como o interior expõe serviços aos consumidores externos. A inversão de dependência (DI) é o mecanismo que viabiliza essa comunicação sem criar acoplamento direto entre domínio e infra. Práticas comuns:
- Defina interfaces para repositórios, gateways e serviços de domínio. O núcleo fornece as assinaturas, as implementações ficam no exterior.
- Use Dependency Injection para injetar dependências em tempo de execução, favorecendo testes com mocks/fábricas.
- Separa models de domínio (entidades) de DTOs/mapeadores usados pela interface com o mundo externo.
- Adapte a entrada/saída (Controller/Presenter) para o formato desejado sem poluir o domínio com detalhes de transporte.
4. Guia rápido de implementação (exemplo em TypeScript)
Abaixo apresento um esqueleto simples que ilustra o alinhamento entre domínio, casos de uso e uma implementação de interface de repositório. Observe como o uso do caso de uso permanece independente da implementação de armazenamento.
// Domínio
class User {
constructor(public id: string, public name: string) {}
}
// Boundaries (interfaces)
interface IUserRepository {
save(user: User): Promise;
findByName(name: string): Promise<User | null>;
}
// Utilitário simples de ID (sem dependências externas)
function generateId(): string {
return Math.random().toString(36).substring(2, 9);
}
// Caso de uso (coordenador do fluxo)
class CreateUser {
constructor(private userRepo: IUserRepository) {}
async execute(name: string): Promise<User> {
const user = new User(generateId(), name);
await this.userRepo.save(user);
return user;
}
}
// Adapter: implementação concreta do repositório (infra)
class InMemoryUserRepository implements IUserRepository {
private users: User[] = [];
async save(user: User): Promise<void> {
this.users.push(user);
}
async findByName(name: string): Promise<User | null> {
const found = this.users.find(u => u.name === name);
return found ?? null;
}
}
// Uso (injeção de dependência, no ponto de comutação com o mundo externo)
(async () => {
const repo = new InMemoryUserRepository();
const cc = new CreateUser(repo);
const alice = await cc.execute("Alice");
console.log("Criado:", alice);
})();
Gostou do conteúdo?
Aprofunde-se em mais posts sobre arquitetura de software. Explore materiais que ajudam a consolidar práticas sólidas e escaláveis.
Recomendo ler:
Sou Apaixonado pela programação e estou trilhando o caminho de ter cada diz mais conhecimento e trazer toda minha experiência vinda do Design para a programação resultando em layouts incríveis e idéias inovadoras! Conecte-se Comigo!