O código espaguete do artigo anterior tinha o fluxo entrelaçado. Então, organizar perfeitamente o fluxo o transforma em código bom?
Este conteúdo dá continuidade ao artigo anterior Code Smell #1.
Não necessariamente.
Você separa as camadas, faz cada uma chamar apenas a camada abaixo e define limites com interfaces, mas o código ainda se torna algo que ninguém quer tocar.
Código que exige alterar sete arquivos para exibir um único campo de texto. Isso é chamado de código lasanha (Lasagna Code) (Texto original do C2).
Código com camadas empilhadas de forma organizada
É exatamente o que o nome sugere. Lasanha é feita empilhando massa e molho em camadas.
A seção transversal é organizada e as camadas são nítidas. O problema é que não dá para retirar apenas uma camada.
Veja um exemplo típico. Um campo nickname foi adicionado aos dados do usuário retornados pelo servidor e precisa ser exibido na tela.
1. UserDTO — Adicionar um campo à estrutura da resposta do servidor
2. UserMapper — DTOAdicionar uma linha ao código que converte para o modelo de domínio
3. User — Adicionar uma propriedade ao modelo de domínio
4. UserRepository — Atualizar aqui também se a assinatura do protocolo mudar
5. FetchUserUseCase — Só passa adiante, mas o tipo exige uma alteração
6. UserViewModel — Converter novamente para o modelo de tela
7. ProfileView — Finalmente, exibir
Do DTO (Data Transfer Object, objeto de transferência de dados) até a tela, a mesma string fica armazenada em três tipos diferentes.
Dos sete arquivos, em quantos realmente há uma decisão? Normalmente em um ou dois.
O restante apenas repassa o valor sem alteração.
Essas camadas são chamadas de camadas de passagem (pass-through layer).
Na literatura de padrões de arquitetura, o estado em que uma requisição apenas atravessa camadas sem processamento também é chamado de antipadrão sinkhole. Esse é o sintoma central do código lasanha.
Por que isso acontece
Ninguém faz isso por má intenção. Na verdade, geralmente é o oposto.
As camadas aumentam principalmente porque bons conselhos são aplicados fora de contexto.
Quando “separe as camadas” é tratado como regra. A pessoa vê um diagrama de Clean Architecture e cria tantas pastas quanto há círculos.
O diagrama não determina quantas camadas devem existir. Ele mostra o princípio de que as dependências devem apontar apenas para dentro (Presentation-Domain-Data Layering).
Mas o significado muda quando isso é transformado em estrutura de pastas.
Quando “dependa de abstrações, não de implementações” é aplicado a tudo. Surgem muitos protocolos com apenas uma implementação.
UserRepositoryUm protocolo e UserRepositoryImpluma implementação. Esse protocolo só cria mais um salto no código.
Isso vale a pena quando o objetivo é inserir uma implementação falsa nos testes. Sem esse plano, é apenas mais uma camada.
Quando se prepara tudo para “poder mudar depois”. Você abstrai o banco de dados caso ele mude e adiciona outra camada caso o servidor mude.
É exatamente disso que YAGNI (You Aren’t Gonna Need It) alerta.
Quando o time cresce e é dividido em camadas. Como diz a Lei de Conway, a estrutura de comunicação da organização fica gravada diretamente na arquitetura.
Com quatro times, é fácil acabar com quatro camadas, cujos limites seguem mais as pessoas do que as necessidades técnicas.
De onde vem o custo
Vamos apontar concretamente o que há de ruim em ter muitas camadas.
O custo de mudança é proporcional ao número de camadas. Um campo exige sete arquivos. Mais assustador é o desenvolvedor tentar evitar isso.
Em vez de passar corretamente por todas as camadas, surge o atalho de chamar a API diretamente no ViewModel.
Quando é trabalhoso seguir as regras, aparece código que as contorna. No fim, as camadas permanecem e o fluxo vira espaguete. A lasanha dá origem ao espaguete.
O custo de leitura aumenta. Para saber de onde veio um valor, é preciso seguir as camadas.
Cada camada é curta e clara, mas depois de sete saltos você esquece qual era a pergunta inicial.
A depuração fica mais lenta. O stack trace aumenta, e encontrar a camada onde o valor deu errado exige pontos de interrupção em todas elas.
O build fica mais lento. Isso é especialmente verdadeiro quando as camadas são divididas em módulos. Cada alteração em uma camada inferior recompila todas as superiores.
Quando as camadas são necessárias — e quando não são
Isso não significa que você deva eliminar as camadas. É preciso ter critérios para decidir.
Uma pergunta costuma funcionar bem.
“Esta camada toma alguma decisão ou apenas repassa algo?”
Tomar uma decisão significa transformar, validar, ramificar ou combinar. Um mapper que converte uma string de data do servidor em Date toma uma decisão.
Um repositório que usa o cache quando disponível e a rede caso contrário também toma uma decisão. Já um UseCase que recebe parâmetros e os repassa sem alteração não decide nada.
Outro critério é o motivo da mudança. A alteração no formato da resposta do servidor e a alteração nas regras de exibição têm motivos diferentes.
Por isso vale a pena separar DTO e modelo de tela. Se o modelo de domínio e o modelo de tela sempre mudam juntos, não há motivo para separá-los.
Resumindo em uma tabela:
| Situação | Vale criar uma camada? |
|---|---|
| O formato externo e o modelo interno evoluem separadamente | Sim |
| Existe um plano real para trocar a implementação | Sim |
| Uma implementação falsa é necessária nos testes | Sim |
| A escala exige registrar os limites do time no código | Depende |
| Existe uma única implementação e sempre existirá | Não |
| A camada apenas recebe e repassa valores sem alteração | Não |
| Ela foi criada porque o diagrama tinha aquela camada | Não |
Como remover camadas
A ordem aproximada para lidar com uma lasanha já montada é esta.
Encontre primeiro as camadas de passagem. Se o corpo do método tem uma linha e ela chama um método de mesmo nome em outro objeto, é uma candidata.
Pesquisar esse padrão no projeto inteiro produz uma lista rapidamente.
Conte as implementações. Veja quantas implementações cada protocolo possui. Se houver apenas uma e ela não for usada nos testes, remova o protocolo e use diretamente o tipo concreto.
É melhor não justificar isso com desempenho. any UserRepositoryAo chamar pelo mesmo tipo existencial, a chamada realmente passa por uma witness table.
Porém, ao usar o protocolo como restrição genérica, ocorre especialização e esse custo desaparece. Já uma classe que não é final continua usando despacho dinâmico por padrão, mesmo chamada pelo tipo concreto.
Além disso, em uma chamada de repositório que atravessa a rede ou o banco de dados, essa diferença não aparece nas medições.
O motivo para remover um protocolo não é desempenho, mas o número de saltos.
Una os tipos. Se DTO e modelo de domínio têm os mesmos campos e sempre mudam juntos, use um só.
Algumas pessoas consideram anexar Codable diretamente ao modelo de domínio uma contaminação. Mas primeiro avalie quando essa contaminação realmente se torna um problema.
Junte dentro de uma camada. Se excluir a camada for difícil, mantenha-a e una os arquivos.
Só colocar protocolo e implementação no mesmo arquivo já reduz o número de saltos.
Resumo
- Código lasanha é código com camadas demais, que exige alterar vários arquivos até para uma pequena mudança.
- Em geral, ele surge não por escrever código ruim, mas por aplicar bons conselhos fora de contexto.
- O sintoma principal é a camada de passagem: uma camada que não decide nada e apenas repassa valores.
- Há dois critérios: essa camada toma decisões e ela muda por um motivo diferente das outras camadas?
- Quando é difícil seguir as regras, surgem atalhos. Com camadas demais, o espaguete acaba crescendo junto.
O próximo artigo trata dos casos em que o problema não está nas camadas, mas nas peças. Veremos o código ravioli: todas as classes são pequenas e bem encapsuladas, mas ninguém consegue explicar o fluxo geral.
Fontes e critérios de verificação
- Lasagna Code — C2 Wiki · original do autor · verificado em 2026-08-17 · base: a metáfora do código lasanha e o problema do excesso de camadas
- Presentation-Domain-Data Layering — Martin Fowler · original do autor · verificado em 2026-08-17 · base: objetivo da separação de camadas e limites de mudança

![Imagem de capa de [Code Smell #2] Código lasanha: por que corrigir sete arquivos para um campo](/assets/images/posts/c81880b5-e5ed-45e7-8f84-04d1a59bc481/lasagna-code-layered-architecture.jpg)