Pratico Clean Architecture faz anos. No TOPO Contábil são 252 use cases seguindo o padrão à risca. Conviver com isso num projeto desse tamanho me ensinou umas coisas que eu não tinha tirado da teoria do livro do Uncle Bob.
O que funciona
Testabilidade é a vitória mais clara. Todo use case é função pura das dependências: injeta mock, asserta output. A suíte unitária roda em 18 segundos porque não toca banco nem rede. Cada use case tem uma responsabilidade e seu arquivo de teste, então uma falha aponta exatamente o que quebrou.
Onboarding. Dev novo fica produtivo em dias, não semanas. A estrutura é tão previsível que quando tu viu um módulo, viu todos. "Onde fica a lógica de negócio?" No use case. "Onde fica a lógica de banco?" No repository. "Onde fica a validação?" No DTO. Sempre. Sem exceção.
Injetar dependências por interface me dá confiança pra refatorar. Trocamos de provedor de cálculo tributário escrevendo um adapter novo, sem mudar lógica de negócio nem testes. Os use cases não sabiam nem ligavam.
Separar entidade de domínio da entidade de banco obriga a pensar no domínio. Nossa entidade de documento fiscal tem comportamento pra se validar, calcular totais e transicionar estados. Não fica dependendo de alguém de fora mutando um saco de propriedades. Isso ajuda com a complexidade da legislação tributária brasileira.
O que não funciona
A cerimônia. Criar feature nova = criar no mínimo 5 arquivos. Use case, DTO de input, DTO de output, método no controller, talvez método novo no repository. Pra CRUD simples é overkill total. A gente aceita esse imposto porque os benefícios em escala superam o custo, mas não vou fingir que não pesa às vezes.
Inferno de mapper. Converter entre entidade de domínio, entidade de banco, DTO e objeto de resposta significa escrever muito código de mapeamento. É tedioso e propenso a erro. Automatizamos parte mas ainda existe uma camada de mapper que existe puramente por pureza arquitetural. Irônico né.
Tentação de over-abstraction. Quando tu tá no mindset Clean Architecture, começa a abstrair tudo. Tu realmente precisa de interface de repository pra tabela de lookup que nunca vai trocar de provedor? Provavelmente não. Mas o padrão diz que sim, aí tu faz, e agora tem interface, implementação e registro de módulo pra algo que podia ser uma chamada direta ao banco.
Quando quebrar as regras
Depois de 252 use cases, desenvolvi senso de quando a arquitetura deve flexibilizar:
Leitura simples que só busca e retorna dado não precisa de use case completo. Query service fino que vai direto pro repository tá de boa. Nem tudo precisa de split comando/query.
Feature protótipo ganha estrutura mais simples. Quando a gente não tem certeza se a feature vai sobreviver, builda com menos cerimônia. Se provar valor, refatora pra Clean Architecture completa. Se não, é fácil deletar.
Caminho crítico de performance às vezes precisa quebrar camada. Nosso módulo de geração de relatório bypassa a abstração de repository e usa SQL puro porque o ORM era lento demais. O purista de arquitetura dentro de mim chora, mas o pragmático sabe que relatório de 30 segundos é pior que camada impura.
Uso Clean Architecture pra deixar o software mais fácil de manter. Onde ela ajuda, sigo; onde pesa sem trazer benefício, flexibilizo. Pureza arquitetural por si só não me ajuda a entregar.
252 use cases depois, faria tudo de novo. Mas seria menos dogmático desde o começo.