Arquitetura simples não é ausência de desenho. É escolher camadas suficientes para deixar responsabilidades claras sem criar caminhos artificiais para toda mudança pequena.
Em serviços web, complexidade costuma aparecer como excesso de abstração, pastas com nomes genéricos, regras espalhadas e contratos implícitos entre controller, serviço, banco e integrações.
Neste artigo
Responsabilidade visível
Uma camada deve existir porque protege uma decisão real: entrada HTTP, regra de negócio, persistência, integração externa ou adaptação de formato. Se ela apenas repassa dados sem acrescentar sentido, talvez esteja escondendo simplicidade.
Nomes também importam. Classes e módulos devem indicar o comportamento que carregam. Quando tudo se chama manager, helper ou utils, o desenho perde valor para quem precisa manter.
Contratos pequenos
Prefira contratos explícitos e estreitos. Um serviço que recebe objetos enormes do request fica preso à interface. Um adaptador que devolve estrutura genérica demais transfere validação para quem consome.
Testes ajudam a manter fronteiras honestas. Se uma mudança simples exige montar metade da aplicação, a arquitetura pode estar cobrando pedágio alto demais.
Evolução gradual
Comece simples e extraia camadas quando a dor aparecer com clareza. Antecipar uma arquitetura grande para um problema pequeno costuma produzir mais acoplamento do que maturidade.
Desenhe o caminho de uma requisição real
Considere uma API que recebe uma solicitação e precisa validar dados, aplicar uma regra e registrar o resultado. A entrada HTTP interpreta o pedido e devolve uma resposta; a regra decide o que é permitido; a persistência grava o estado. Uma integração externa, se existir, tem contrato e tratamento de falha próprios. Esse caminho é simples de explicar porque cada limite protege uma decisão observável. Criar uma camada adicional que apenas repassa o mesmo objeto não acrescenta clareza.
O teste dessa operação deve conseguir verificar a regra sem subir servidor, banco e serviço externo ao mesmo tempo. Um segundo teste pode exercitar o contrato entre as partes. Se cada alteração pequena exige preparar metade da aplicação, a fronteira escolhida pode estar errada; se tudo fica em um único método, provavelmente as decisões estão misturadas.
Quando vale separar mais
Uma abstração passa a fazer sentido quando a mesma regra é repetida em fluxos diferentes, quando uma integração muda sem que a regra de negócio deva mudar ou quando o erro exige diagnóstico independente. Anote o motivo concreto da separação: facilitar teste, conter falha, preservar contrato ou reduzir duplicação. Evite criar interfaces para toda classe apenas porque o projeto usa um padrão; isso aumenta arquivos sem reduzir dependências.
Evolua a estrutura com uma mudança pequena
Comece por identificar uma alteração recorrente que hoje atravessa muitas pastas. Proteja o comportamento esperado com um teste, mova uma responsabilidade por vez e observe se o próximo ajuste ficou mais localizado. Revise também configuração e observabilidade: um serviço de poucas camadas ainda precisa dizer que versão está rodando, por que recusou uma solicitação e qual dependência falhou. Simplicidade não é contagem de arquivos; é conseguir modificar o sistema com impacto compreensível.