Crie uma conta gratuita ou Faça login
Podcast
Tech Leadership Rocks
Episódio 236

Arquitetura de software e abstrações com Xavier Araújo

• 52 minutos

Neste episódio, Eduardo Matos conversa com Xavier Araújo, Software Engineering Lead na Fanduel, sobre arquitetura de software, com foco na arquitetura hexagonal e suas implicações práticas. Xavier compartilha suas experiências e aprendizados de um projeto com mais de 4 anos usando arquitetura hexagonal e lista os aprendizados que teve em contrassenso com o mercado, como o suposto benegício das abstrações, por exemplo.

Reaja nos momentos marcantes
Curti
Boa ideia
Amei
Engraçado
Parabéns
Mind blown

Se uma interface só tem uma implementação e não há perspectiva de mudança, a indireção pode ser desnecessária.

— Xavier Araújo

Capítulos

00:00 Introdução
00:45 Quem é Xavier Araújo
02:25 Estudo de caso sobre arquitetura hexagonal
08:32 Como arquitetar uma aplicação para adicionar testes
10:31 Quando usar indireções no código
16:27 Como evitar que abstrações "vazem"
21:21 Como facilitar a manutenção de um software
28:08 Como identificar e evitar overengineering
35:54 Outras opiniões polêmicas sobre tecnologia
47:15 Conselho sobre arquitetura e desenvolvimento de software
50:41 Mensagem final

Resumo deste episódio

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.

Para ler todo o resumo Crie uma conta grátis ou Faça login