Crítica à arquitetura hexagonal
A arquitetura hexagonal (ou "Ports and Adapters") promete facilitar a evolução de sistemas ao isolar o núcleo de negócios de dependências externas (como bancos de dados ou APIs). Porém, na prática, ela pode gerar complexidade desnecessária:
- Boilerplate excessivo: Muitas abstrações são criadas "por regra", mesmo quando não há perspectiva real de substituição de tecnologias (ex.: trocar um banco relacional por NoSQL).
- Microserviços reduzem sua utilidade: Em sistemas distribuídos, a agilidade para modificar serviços diminui a necessidade de abstrações antecipadas.
- Foco no contexto real: Abstrações só valem a pena quando há múltiplas implementações existentes ou alta probabilidade de mudança. Caso contrário, são overengineering.
Testes e injeção de dependência: o real benefício
A ideia de que arquiteturas hexagonais facilitam testes é questionada.
- Dependency Injection é o cerne: A capacidade de mockar dependências vem da injeção, não das interfaces da arquitetura hexagonal. Ferramentas modernas permitem mockar classes concretas sem interfaces.
- Simplicidade nos testes: Abstrações complexas podem até dificultar a escrita de testes, pois aumentam a indireção no código.
Quando abstrações fazem sentido
Nem toda abstração é ruim, mas seu uso deve ser pragmático:
- Evite indireção desnecessária: Navegar por camadas de interfaces e implementações aumenta a carga cognitiva. Se uma interface tem apenas uma implementação concreta, a indireção pode ser dispensada.
- Casos de uso válidos: Abstrações são úteis quando:
- Existem múltiplas implementações (ex.: diferentes provedores de e-mail).
- Facilitam o desenvolvimento local (ex.: substituir AWS SQS por filas em memória em ambientes de teste).
- Regra de ouro: Pergunte-se: "O que ganho com esta abstração?" Se a resposta for vaga, provavelmente não vale a pena.
O perigo das abstrações que "vazam"
Abstrações mal definidas podem criar falsas expectativas:
- Acoplamento oculto: Mesmo com interfaces, tecnologias subjacentes impõem limitações. Exemplo:
- Trocar Kafka (que garante ordem de mensagens) por RabbitMQ (que não suporta o recurso) exigirá ajustes no código de negócios.
- Migrar de um banco transacional (MySQL) para um não transacional (Cassandra) inviabiliza a troca "plug-and-play".
Abstrações não são balas de prata. Elas devem refletir a realidade tecnológica, não idealizações.
simplicidade como filosofia
A busca pelo mínimo viável é crucial para sistemas sustentáveis:
- Comece simples: Use soluções diretas (ex.: cron jobs para processamento em segundo plano em vez de filas complexas).
- Escale sob demanda: Bancos como PostgreSQL atendem bem a maioria dos casos. Só migre para tecnologias especializadas quando limites reais forem atingidos.
- Código compreensível: Sistemas simples reduzem o bus factor (dependência de poucas pessoas) e aceleram o onboarding.
Identificando overengineering
Sinais de que você está complicando além do necessário:
- Soluções desproporcionais: Implementar resiliência extrema para sistemas não críticos (ex.: um app interno com uptime de 99,999% gera custos altos sem benefício real).
- Ferramentas inadequadas: Usar Kafka quando filas simples resolvem, ou adotar frameworks JavaScript pesados para aplicações pequenas, introduz complexidade desnecessária.
- Pergunta-chave: "Qual o pior cenário se isso falhar?" Se o impacto for baixo, opte pela simplicidade.
Requisitos não-Funcionais como guia
Decisões arquiteturais devem ser orientadas por necessidades reais:
- Contexto é tudo: Entenda a criticidade do sistema. Um relatório processado em horas pode rodar em batch simples; um em tempo real exige otimização.
- Comunicação com stakeholders: Engenheiros devem traduzir implicações técnicas (custo, tempo de desenvolvimento) para evitar expectativas irreais.
- Soft skills: Saber extrair requisitos não-técnicos é tão importante quanto as habilidades técnicas.
Conselhos para aspirantes a arquitetos
- Fundamentos primeiro: Domine algoritmos, estruturas de dados e padrões antes de focar em design de sistemas.
- Pratique com mentoria: Faça exercícios de system design e peça feedback a profissionais experientes.
- Mindset de produto: Você não é pago para escrever código, mas para resolver problemas. Entenda o negócio.
Conclusão
Não há regras universais. Abstrações, arquiteturas hexagonais ou tecnologias complexas têm lugar desde que justificadas pelo contexto. A verdadeira habilidade está em equilibrar teoria com pragmatismo, questionando sempre: "Isso agrega valor real?" Simplicidade, quando aliada a uma compreensão profunda do problema, costuma ser a escolha mais sábia.