Home Comunidade Eventos YouTube Networks Desafios // produtos Academy News CTI | CVE Contato

01 - O que é Arquitetura de Software

#adr#arquitetura#decisões#qualidade#trade-offs
video explicativo
Video explicativoEspaco reservado para o video desta anotação — adicione video: https://youtu.be/... no frontmatter da nota.

O que é Arquitetura de Software

Arquitetura de software é o conjunto de decisões estruturais que define a organização fundamental de um sistema: seus componentes, suas fronteiras, seus mecanismos de comunicação e os contratos que unem essas partes. São as decisões mais caras de reverter, porque se espalham por dezenas de módulos, moldam o pipeline de deploy, condicionam o modelo de dados e determinam como as equipes se organizam. Em produção, a qualidade dessas escolhas aparece em indicadores concretos: tempo de recuperação após falha, latência em picos de tráfego, custo mensal de infraestrutura e velocidade com que as squads entregam mudanças sem quebrar vizinhos. Um sistema bem arquitetado não é o mais sofisticado; é aquele cujos trade-offs correspondem aos requisitos reais do negócio e à maturidade operacional do time. Por isso arquitetura é, antes de tudo, engenharia de decisões sob incerteza, com validação contínua em produção em vez de promessas fechadas em documentos.

Arquitetura versus Design

A distinção mais útil não está no diagrama, e sim no impacto e no custo de reversão. Decisões arquiteturais são aquelas cuja mudança posterior exige alterar a estrutura do sistema, coordenar várias equipes ou migrar dados em produção. Decisões de design são locais, ficam escondidas atrás de abstrações e podem ser trocadas em uma única revisão de código. Escolher entre monolito e microsserviços, definir que o pagamento usa fila em vez de chamada síncrona ou fixar PostgreSQL como fonte de verdade são escolhas arquiteturais. Trocar um algoritmo, extrair uma função ou renomear um método interno são decisões de design.

O critério prático é a dificuldade de desfazer: se mudar depois significa semanas de migração, contratos quebrados e janela de manutenção, a decisão é arquitetural. Essa fronteira é fluida e depende do contexto do código. Em um monolito modular com fronteiras bem testadas, trocar o ORM pode ser design; no mesmo código sem fronteiras, vira projeto de meses. Reconhecer essa diferença antes que o custo se materialize é parte central do trabalho arquitetural.

Pares de exemplos que ilustram a fronteira na prática:

  • Escolher Kafka versus RabbitMQ para integrações: arquitetural, porque define capacidades de replay, ordenação e throughput para todo o ecossistema de eventos.
  • Escolher entre biblioteca de serialização no código de um consumidor: design, porque a troca é local e fica escondida atrás da interface de publicação.
  • Definir consistência eventual entre pedidos e estoque: arquitetural, porque muda contratos, experiência do usuário e tratamento de falhas em vários serviços.
  • Escolher entre recursão e iteração dentro de um método: design puro; se a implementação estiver errada, o custo de corrigir é um commit.

O Problema que a Arquitetura Resolve

Sem decisões estruturais explícitas, o sistema cresce por acúmulo: cada feature escolhe o caminho de menor resistência, módulos passam a chamar módulos sem critério e o resultado é a bola de lama, em que mudanças simples produzem efeitos imprevisíveis em pontos distantes. A arquitetura administra essa entropia estabelecendo fronteiras, regras de dependência e padrões que a equipe aplica sem precisar consultá-la a cada commit. Ela também resolve um problema de coordenação: um vocabulário compartilhado de componentes e contratos permite que times distintos evoluam partes separadas do sistema sem reuniões de reconciliação constantes.

Há ainda a função de gestão de risco. Requisitos funcionais dizem o que o sistema faz; atributos de qualidade dizem como ele se comporta sob pressão, e é o comportamento sob pressão que gera incidentes, multas contratuais e perda de clientes. A arquitetura é o principal instrumento para priorizar e sustentar esses atributos ao longo do tempo, mesmo quando a pressão por features tenta sacrificá-los em nome de prazos curtos.

Funções concretas que a arquitetura cumpre quando está funcionando:

  • Economia de decisão: padroniza o que é repetitivo para que o time gaste debate apenas no que é específico da feature da vez.
  • Registro do raciocínio: preserva o porquê das escolhas, permitindo reavaliá-las futuramente com o mesmo contexto original à vista.
  • Controle de risco: concentra atenção nos cenários de falha mais custosos para o negócio, em vez de tratar todos os riscos como iguais.
  • Facilitação da evolução: define onde o sistema pode crescer sem reescrita, orientando investimento estrutural incremental em vez de big bang.

Decisões Estruturais e sua Documentação

Decisão arquitetural séria precisa de registro com contexto, opções consideradas, escolha e consequências aceitas. O formato consagrado é o ADR (Architecture Decision Record), arquivo curto e imutável que vive junto do código e permite que qualquer pessoa, meses depois, entenda por que o sistema é do jeito que é. Sem esse registro, o conhecimento mora na memória de poucas pessoas e se perde em troca de equipe; decisões pensadas como temporárias viram permanentes por pura falta de informação.

# ADR-007: comunicação entre pedidos e estoque
id: ADR-007
status: aceita            # proposta, aceita ou substituída (ex.: por ADR-013)
data: 2025-03-14
contexto: >
  O serviço de pedidos reserva estoque por chamada síncrona (gRPC).
  Em picos, o estoque degrada e derruba o checkout junto.
opcoes:
  - manter gRPC com circuit breaker e retentativas
  - publicar evento PedidoCriado e reservar de forma assíncrona
  - manter gRPC e adicionar cache de reserva
decisao: publicar evento PedidoCriado via broker, com padrão outbox
consequencias:
  - estoque deixa de ser ponto único de falha do checkout
  - reserva passa a ser eventual; a UI comunica confirmação posterior
  - o consumidor de reservas precisa ser idempotente

Reversibilidade merece tratamento explícito. Decisões de duas vias, fáceis de reverter, podem ser tomadas rápido e ajustadas depois; decisões de uma via, como banco de dados, estilo arquitetural e protocolo entre serviços centrais, exigem protótipo, dados e discussão antes do compromisso. O erro frequente é gastar semanas deliberando sobre uma decisão de duas vias e aprovar em dez minutos uma decisão de uma via.

Atributos de Qualidade

Atributos de qualidade são as propriedades não funcionais que a arquitetura sustenta: disponibilidade, latência, consistência, segurança, escalabilidade, observabilidade e manutenibilidade. Nenhum vem de graça; cada um é pago com design, infraestrutura e complexidade operacional, e todos competem pelos mesmos recursos. Consistência forte custa latência porque exige coordenação entre nós; alta disponibilidade tensiona a consistência porque particionamento de rede é inevitável; segurança rígida pode impor atrito que degrada a experiência. O papel do arquiteto é transformar requisitos vagos em números: "o sistema precisa ser rápido" não é requisito; "o checkout responde em p95 abaixo de 300 ms na Black Friday" é.

Atributo Pergunta que responde Métrica típica Trade-off principal
Disponibilidade O sistema responde agora? Uptime, SLO de 99,9% Custo de redundância e failover
Latência Responde rápido o suficiente? p95 e p99 em milissegundos Chamadas em cadeia e coordenação
Consistência O dado está correto em toda parte? Taxa de conflitos, staleness Coordenação custa latência e uptime
Segurança Resistimos a acesso indevido? Tempo de detecção, cobertura de IAM Atrito do usuário, custo de segredos
Escalabilidade Suporta 10x a carga? Throughput por nó, custo por requisição Sharding e estado distribuído
Manutenibilidade O time entrega sem medo? Lead time, taxa de rollback Indireção e custo de abstrações

Conflitos entre atributos aparecem em produção de forma bem concreta:

  • Consistência contra latência: transações distribuídas garantem que estoque e pagamento concordem, mas cada coordenação adicional soma milissegundos ao checkout.
  • Disponibilidade contra consistência: aceitar escritas durante partição de rede preserva vendas e cria divergências que precisam ser conciliadas depois.
  • Segurança contra operação: rotacionar segredos a cada hora reduz a janela de comprometimento e multiplica chances de incidente de configuração.
  • Escalabilidade contra custo: dimensionar para o pico anual significa pagar capacidade ociosa nos onze meses restantes.

Só com números é possível escolher entre alternativas e verificar, depois, em produção, se a decisão cumpriu o prometido. Sem eles, discussões arquiteturais viram disputa de opiniões, e vence a proposta mais eloquente, não a mais adequada ao problema.

O Custo da Mudança

O argumento clássico afirmava que o custo de mudança cresce exponencialmente com o tempo de projeto. Para mudanças estruturais tomadas sem critério, a curva continua verdadeira: extrair um serviço de um monolito acoplado ou trocar o modelo de consistência segue sendo trabalho de meses. Práticas modernas achatam a curva para o resto do sistema: testes automatizados, integração contínua, deploy frequente e modularização reduzem o custo de mudanças locais e de médio porte, porque o sistema avisa quando algo quebra, em vez de falhar em produção sem aviso.

Daí o critério de projeto mais valioso em produção: reversibilidade. Prefira soluções que permitam voltar atrás, use feature flags para separar deploy de lançamento, mantenha contratos versionados para que consumidores migrem no próprio ritmo e trate migrações de dados como processos em duas fases, expandir e depois contrair, em vez de cortes únicos. Reversibilidade não dispensa decidir bem; ela garante que errar rápido seja barato o suficiente para corrigir rápido.

O Papel do Arquiteto como Facilitador Técnico

O modelo de torre de marfim, em que o arquiteto desenha diagramas e entrega ao time para implementar, falha por dois motivos: o diagrama ignora detalhes que só aparecem no código, e o time não internaliza as razões das restrições, contornando-as quando a pressão chega. O papel moderno é o de facilitador técnico: alguém que escreve código com o time, traduz requisitos de negócio em atributos de qualidade mensuráveis, ensina os critérios de decisão e remove obstáculos estruturais que travam a entrega. A autoridade vem da argumentação e do resultado medido, não do cargo.

Esse papel exige repertório amplo: estilos arquiteturais e seus trade-offs, operação de produção, custo de infraestrutura e dinâmica de equipes. Também exige disposição para mudar de ideia; decisões tomadas sob incerteza precisam ser revisadas quando a produção traz dados novos, e defender uma escolha apenas pelo orgulho de tê-la feito é antipadrão de liderança técnica.

Responsabilidades contínuas desse papel:

  • Definir e defender restrições estruturais: fronteiras de módulo, regras de dependência e contratos entre serviços; restrições bem escolhidas liberam a equipe de decidir o básico a cada tarefa e concentram o esforço onde há valor.
  • Medir em vez de opinar: definir métricas de produção, como latência p95, taxa de erro e custo por transação, que verificam se as decisões cumprem o prometido, com verificações automatizadas quando possível.
  • Cuidar da dívida estrutural: manter lista visível de débitos arquiteturais com custo estimado, para que a organização decida com dados quando pagá-los, em vez de descobrir no incidente.
  • Formar substitutos: difundir o raciocínio arquitetural no time, porque conhecimento concentrado em uma pessoa cria gargalo e ponto único de falha, inclusive nas férias dela.

Arquitetura em Execução: Verificação Contínua

Decisões arquiteturais degradam silenciosamente quando ninguém verifica se elas continuam respeitadas. A resposta prática são fitness functions: verificações automatizadas que medem o quanto a implementação adere às características desejadas e que rodam no pipeline, junto dos testes. Elas transformam regras estruturais em código executável, que falha o build quando violada, em vez de depender de revisão humana atenta em cada pull request.

# Exemplos de fitness functions configuradas em um pipeline de CI
verificar:
  dependencias:
    - modulo-vendas nao importa modulo-faturamento.interno        # fronteira de módulo
    - nenhuma classe de negocio importa pacote web.framework      # independência de framework
  performance:
    - p99 do endpoint /checkout abaixo de 300 ms no teste de carga noturno
  seguranca:
    - nenhuma dependencia com CVE critica no lockfile do artefato
  observabilidade:
    - todo endpoint novo emite trace com identificador de correlacao

O conjunto de verificações deve refletir os atributos priorizados para aquele sistema; cobrir tudo é caro e dilui o sinal. Comece pelas duas ou três violações que causaram incidentes reais nos últimos meses e cresça a lista a partir delas. Verificação contínua também muda a conversa sobre arquitetura: em vez de apelos morais para respeitar o desenho, o desenho passa a ter contratos testáveis que o próprio pipeline defende.

Erros Comuns e Boas Práticas

Sintoma em produção Causa provável Mitigação
Toda feature exige mexer em dez módulos Fronteiras inexistentes ou furadas Redesenho incremental com regras de dependência testadas
Incidentes repetem a mesma classe de falha Atributos de qualidade nunca quantificados Definir SLOs e revisar a arquitetura contra eles
Reuniões reabrindo a mesma decisão Ausência de ADR ou ADR sem status Registrar contexto, opções e consequências aceitas
Time contorna a arquitetura oficial Decisões impostas sem participação Decisão colaborativa com protótipos e dados de produção
Migração de banco com downtime longo Mudança de uma via aplicada como corte único Estratégia expandir e contrair com escrita dupla temporária
Onboarding lento e dependência de uma pessoa Conhecimento concentrado no arquiteto ADRs, rodízio de módulos e documentação enxuta
Capacidade estourando no primeiro pico real Dimensionamento baseado em estimativa Testes de carga com tráfego medido e plano de escala

Boas práticas que sustentam o dia a dia:

  • Decida no último momento responsável: adiar mantém opções abertas e chega com mais informação; adiar demais custa retrabalho em paralelo.
  • Valide na produção, não no slide: diagramas não provam nada; métricas de latência, erro e custo provam.
  • Torne a arquitetura verificável: regras estruturais que ninguém consegue testar serão violadas no primeiro prazo apertado.
  • Trate contratos como produto: versionamento, compatibilidade retroativa e aviso de mudanças evitam que evoluções quebrem consumidores em silêncio.
  • Escreva ADRs curtos: uma página por decisão, com data e status explícito; documento longo não é lido e não é mantido vivo.
  • Projete para o pico medido, não para o imaginado: dimensione com base em tráfego observado, mantendo caminho claro para dobrar capacidade quando o negócio crescer.