Estilos arquiteturais e padrões existem para resolver
problemas reais — mas cada um carrega custo. As
decisões abaixo cobrem os trade-offs que mais aparecem
em entrevista e em pull requests reais.
Hexagonal ou Layered?
Layered é a escolha default sensata para equipes
menores e sistemas com fronteiras simples — é mais
fácil de entender sem onboarding especializado.
Hexagonal compensa quando: o sistema tem múltiplos
adaptadores de entrada (HTTP, gRPC, fila, CLI) e
múltiplos de saída (PostgreSQL, Redis, Kafka, email);
quando testabilidade de domínio sem banco é requisito;
e quando o time já entende a metáfora. Em prática,
sistemas que começam em Layered migram para Hexagonal
quando sentem que Infrastructure vaza para Domain.
Não adote Hexagonal em sistemas CRUD simples —
o overhead de ports e adapters não paga.
Microservices ou Modular Monolith?
Monolito modular é a escolha correta para a maioria
dos sistemas novos. Microservices resolvem três
problemas específicos: escala de deploy independente
(times diferentes, cadências diferentes), escala de
carga diferenciada (módulo de vídeo precisa de mais
GPU que o módulo de auth), e isolamento de falha
entre domínios críticos. Para qualquer coisa fora
dessas três condições, o custo operacional de
microservices (service mesh, tracing distribuído,
deploy complexo, debugging cross-service) supera o
benefício. Um monolito com módulos bem delimitados
pode virar microservices depois — um monolito
distribuído dificilmente volta.
Quando DDD justifica o investimento?
DDD completo — com Aggregates, Domain Events,
Ubiquitous Language, Bounded Contexts — paga quando
o domínio é genuinamente complexo e muda com
frequência: fintech, saúde, e-commerce com regras
de negócio ricas. Em CRUD simples, DDD é
over-engineering que faz junior demorar mais para
entender o código. O sinal prático: se você passa
mais tempo modelando regras de negócio do que
escrevendo queries, DDD ajuda. Se o sistema é
primariamente de leitura e exibição, uma arquitetura
mais plana (ou CQRS sem event sourcing) é
provavelmente mais honesta.
Strangler Fig ou reescrita completa?
Strangler Fig é a escolha conservadora e muitas
vezes correta: risco menor, entrega contínua, base
de usuários estável. Mas tem custo real: manter dois
sistemas em paralelo por meses, sincronizar dados,
testar integração entre novo e velho. Reescrita
completa ("big bang") faz sentido quando: o legado
é tão acoplado que não tem interfaces para interceptar;
o domínio mudou tanto que a lógica existente é
irrelevante; ou a dívida técnica é tão severa que
cada nova feature no legado custa 5× o que custaria
em sistema limpo. A decisão honesta é medir o custo
de cada caminho — não romanticizar nenhum dos dois.
Design Patterns: descobrir ou aplicar?
Patterns são descobertos, não aplicados. O caminho
saudável: você tem código duplicado ou difícil de
estender, extrai a abstração, e então reconhece
"isso é um Strategy" ou "isso é um Factory Method".
O caminho anti-saudável: você decide que vai usar
Strategy antes de ter o problema, e força o padrão
em código que seria mais simples sem ele. Padrões
GoF nomeiam soluções recorrentes — eles existem para
facilitar comunicação ("extrai para Strategy aqui")
e para guiar refatoração ("esse if gigante pode virar
Chain of Responsibility"). Nunca como objetivo final.