Arquitetura em camadas: organizar responsabilidades
Arquitetura em camadas é um padrão de organização em que o sistema é dividido por responsabilidades, reduzindo acoplamento e facilitando manutenção, testes e evolução. Em cenários bancários, é comum separar regras de negócio de detalhes técnicos (banco, mensageria, integrações), para permitir mudanças com menor risco.
Camadas típicas e responsabilidades
Apresentação (UI/API): recebe requisições, valida formato, autentica/autoriza (quando aplicável), traduz para comandos de negócio e devolve respostas. Evite regra de negócio aqui.
Aplicação (casos de uso): orquestra fluxos (ex.: “registrar pagamento”, “abrir conta”), coordena transações e chamadas a serviços. Concentra regras de processo (workflow).
Domínio (regras de negócio): entidades, regras e invariantes (ex.: limites, validações de consistência). Deve ser o mais independente possível de frameworks.
Infraestrutura: detalhes técnicos (persistência, mensageria, integrações externas, cache, provedores). Implementa interfaces definidas pelas camadas superiores.
Continue em nosso aplicativo
Você poderá ouvir o audiobook com a tela desligada, ganhar gratuitamente o certificado deste curso e ainda ter acesso a outros 5.000 cursos online gratuitos.
ou continue lendo abaixo...Baixar o aplicativo
Exemplo prático: fluxo em camadas
Cenário: um serviço de Pagamentos recebe uma solicitação para registrar um pagamento e notificar outros sistemas.
API: valida campos obrigatórios e converte JSON em um comando (ex.:
RegistrarPagamento).Aplicação: chama o domínio para validar regras, persiste e publica um evento (ex.:
PagamentoRegistrado).Domínio: garante invariantes (ex.: impedir duplicidade por chave de negócio).
Infra: grava no banco e envia mensagem para um broker (fila/tópico).
Passo a passo prático: desenhando camadas para um caso de uso
1) Liste casos de uso: “Criar proposta”, “Aprovar proposta”, “Efetivar contrato”.
2) Defina entradas/saídas: dados necessários, resposta esperada, erros.
3) Separe regras: o que é invariável (domínio) vs o que é fluxo (aplicação).
4) Defina portas (interfaces): repositórios, publicadores de eventos, clientes de serviços externos.
5) Implemente adaptadores: banco, mensageria, HTTP clients.
6) Garanta testabilidade: domínio e aplicação testáveis sem dependências externas (mock das portas).
Monólito vs microserviços: comparação objetiva
Monólito e microserviços são estilos arquiteturais. A escolha impacta implantação, escalabilidade, governança, confiabilidade e complexidade operacional.
Monólito
O que é: uma aplicação única (um artefato/implantação) com módulos internos.
Vantagens: deploy mais simples, transações locais mais fáceis, depuração direta, menor sobrecarga de rede.
Desvantagens: escalabilidade geralmente “em bloco”, risco de acoplamento entre módulos, releases podem ficar pesados, falhas podem impactar mais áreas se não houver isolamento interno.
Microserviços
O que é: conjunto de serviços pequenos e independentes, cada um com responsabilidade clara, comunicando-se via rede (HTTP/gRPC/mensageria).
Vantagens: escalabilidade por serviço, deploy independente, isolamento de falhas (se bem projetado), autonomia de times.
Desvantagens: maior complexidade (latência, retries, versionamento de contratos), dados distribuídos, consistência eventual, necessidade forte de observabilidade e automação.
Critérios práticos de escolha
Limites de domínio claros: se há responsabilidades bem separadas e evolução independente, microserviços tendem a ser adequados.
Escalabilidade desigual: se um componente precisa escalar muito mais que outros (ex.: processamento de eventos), microserviços ajudam.
Maturidade operacional: sem automação de deploy, monitoramento e resposta a incidentes, microserviços aumentam risco.
Velocidade inicial: para começar com menor custo operacional, um monólito modular costuma ser melhor.
Comparação direta (resumo)
Deploy: monólito (1 unidade) vs microserviços (múltiplas unidades).
Falhas: monólito (impacto potencial maior) vs microserviços (isolamento possível, mas risco de cascata via rede).
Dados: monólito (transações locais) vs microserviços (integração por eventos, consistência eventual).
Performance: monólito (chamadas internas rápidas) vs microserviços (latência de rede, serialização, retries).
Complexidade: monólito (menor) vs microserviços (maior, exige governança e observabilidade).
Integração síncrona vs assíncrona
Integração é como sistemas trocam informações e coordenam ações. A distinção central é: esperar resposta imediata (síncrona) ou desacoplar por mensagens/eventos (assíncrona).
Integração síncrona
Conceito: o sistema A chama o sistema B e aguarda resposta (ex.: HTTP/gRPC). O resultado depende da resposta imediata.
Quando usar: consulta em tempo real, validações que precisam de resposta imediata, operações curtas.
Implicações: precisa de timeout, retry com cuidado e circuit breaker para evitar falhas em cascata; latência do B vira latência do A.
Integração assíncrona
Conceito: o sistema A publica uma mensagem/evento e segue; o sistema B processa depois, via broker.
Quando usar: processamento demorado, picos de carga, desacoplamento entre sistemas, workflows distribuídos.
Implicações: consistência eventual, duplicidade de mensagens, necessidade de idempotência e rastreabilidade ponta a ponta.
Passo a passo prático: decidir síncrono ou assíncrono
1) Precisa responder ao usuário agora? Se sim, tende a ser síncrono ou híbrido (responde “recebido” e processa assíncrono).
2) A operação pode demorar ou ter picos? Se sim, assíncrono reduz timeouts e melhora resiliência.
3) A dependência é instável? Assíncrono ajuda a absorver indisponibilidades temporárias.
4) Exige consistência forte imediata? Síncrono facilita, mas evite transações distribuídas; prefira compensações quando possível.
5) Precisa auditar e rastrear? Ambos precisam, mas assíncrono exige correlação de eventos e observabilidade mais robusta.
Mensageria: filas, tópicos e padrões de comunicação
Mensageria é o uso de um intermediário (broker) para transportar mensagens entre produtores e consumidores. Ela permite desacoplamento, buffer de carga e maior tolerância a falhas.
Fila (queue)
Modelo: ponto a ponto. Uma mensagem é consumida por um consumidor (dentro de um grupo concorrente).
Uso típico: processamento de tarefas (ex.: gerar documento, processar lote), balanceamento de carga entre workers.
Implicação: aumenta throughput com consumidores paralelos; exige controle de concorrência e idempotência.
Tópico (topic)
Modelo: publicação/assinatura. Uma mensagem pode ser entregue a vários consumidores (cada um com sua assinatura/grupo).
Uso típico: eventos de negócio (ex.:
PagamentoConfirmado) consumidos por antifraude, notificações, conciliação, analytics.Implicação: facilita integração entre múltiplos sistemas sem acoplamento direto; exige governança de contratos de eventos.
Comandos vs eventos
Comando: “faça algo” (intenção). Ex.:
ProcessarPagamento. Normalmente direcionado a um responsável.Evento: “algo aconteceu” (fato). Ex.:
PagamentoProcessado. Pode interessar a vários consumidores.
Garantias de entrega: pelo menos uma vez vs exatamente uma vez (conceitual)
Ao usar mensageria, é essencial entender as garantias de entrega, pois elas afetam duplicidade, perda e complexidade de processamento.
Pelo menos uma vez (at-least-once)
Conceito: a mensagem será entregue uma ou mais vezes. Duplicatas podem ocorrer (ex.: consumidor processa, mas falha antes do ack).
Implicação: o consumidor deve ser idempotente (processar duplicatas sem efeitos colaterais indevidos).
Vantagem: reduz chance de perda; é comum e mais simples de operar.
Exatamente uma vez (exactly-once) em nível conceitual
Conceito: o efeito do processamento ocorre uma única vez, mesmo com falhas e retries.
Interpretação prática: muitas vezes significa “exatamente uma vez no efeito” (sem duplicar gravações/ações), usando deduplicação, controle de offsets e/ou transações no pipeline.
Custo: maior complexidade e, frequentemente, impacto em desempenho/latência.
Idempotência: o antídoto contra duplicidade
Uma operação idempotente pode ser executada várias vezes com o mesmo resultado final. Em mensageria, isso é crucial porque duplicatas são esperadas em muitas configurações.
Estratégias comuns de idempotência
Chave idempotente: incluir um identificador único (ex.:
eventId,requestId) e registrar o que já foi processado.Deduplicação por chave de negócio: usar uma chave natural (ex.: “id da transação”) para impedir reprocessamento.
Upsert/merge: gravar de forma que repetição não crie novos registros (inserir se não existe, senão atualizar).
Inbox/Outbox (conceito): controlar consumo/publicação com persistência de estado para reduzir janelas de inconsistência entre banco e broker.
Passo a passo prático: consumidor idempotente (modelo mental)
1) Receba a mensagem com
eventIde dados.2) Verifique se o
eventIdjá foi processado (registro de deduplicação/inbox).3) Se já processado, finalize sem repetir efeitos.
4) Se não processado, aplique a mudança (ex.: atualizar status, gerar lançamento).
5) Registre o
eventIdcomo processado com metadados (timestamp, origem).6) Confirme (ack) a mensagem após persistir o estado, reduzindo risco de duplicar efeitos.
// Pseudofluxo conceitual de idempotência no consumo onMessage(msg): if inbox.exists(msg.eventId): ack(msg) return beginTransaction() applyBusinessEffect(msg) inbox.save(msg.eventId, processedAt=now) commit() ack(msg)Consistência eventual: o que esperar em integrações assíncronas
Consistência eventual significa que, após uma mudança, diferentes partes do sistema podem ficar temporariamente divergentes, mas convergem com o tempo. Isso é comum quando eventos propagam alterações entre serviços.
Exemplo prático
Serviço A registra “pagamento aprovado” e publica um evento.
Serviço B (notificações) consome o evento e envia mensagem alguns segundos depois.
Durante esse intervalo, o usuário pode ver o pagamento aprovado, mas ainda não recebeu a notificação.
Cuidados e técnicas associadas
Estados intermediários: modelar status como “PENDENTE/PROCESSANDO/CONFIRMADO” para refletir o fluxo real.
Reprocessamento seguro: permitir retry sem efeitos duplicados (idempotência).
Compensação: se uma etapa posterior falhar, executar ação compensatória (ex.: estornar) em vez de depender de transação distribuída.
Observabilidade: logs, métricas e traces
Observabilidade é a capacidade de entender o que está acontecendo em produção a partir de sinais gerados pelo sistema. Em arquiteturas distribuídas, ela é indispensável para detectar falhas, medir desempenho e investigar incidentes.
Logs
O que registrar: início/fim de processamento, erros, timeouts, retries, decisões de negócio relevantes, IDs de correlação.
Boa prática: logs estruturados com campos como
service,operation,eventId,correlationId,durationMs.
Métricas
Exemplos: taxa de requisições, latência p95/p99, taxa de erro, tamanho de fila/lag, throughput de consumo, retries por minuto.
Uso: alertas, capacidade, detecção de degradação e gargalos.
Traces (rastreamento distribuído)
Conceito: acompanha um fluxo ponta a ponta, atravessando serviços, filas e chamadas externas, medindo tempos e identificando gargalos.
Valor: localizar onde a latência aumenta (dependência externa, banco, consumidor lento, serialização).
Correlação de eventos: conectar o que aconteceu
Correlação usa identificadores para relacionar logs, mensagens e spans de trace do mesmo fluxo. Em mensageria, isso é essencial para investigar duplicidade, atrasos e falhas intermitentes.
IDs comuns:
correlationId: identifica a jornada/fluxo de negócio.causationId: identifica o evento/comando que causou o evento atual.eventId: identifica unicamente a mensagem (útil para deduplicação).
Passo a passo prático: propagação de correlação:
1) Na entrada (API), gere/extraia um
correlationId.2) Inclua o
correlationIdem logs e em chamadas síncronas (headers).3) Ao publicar mensagem, inclua
correlationId,eventIdecausationIdnos metadados.4) No consumidor, reutilize o
correlationIdem logs/traces e propague para novos eventos.5) Em erros, registre também tentativa, fila/tópico e motivo do retry para facilitar reprocessamento.
// Exemplo conceitual de metadados de mensagem { "eventId": "uuid-...", "correlationId": "uuid-...", "causationId": "uuid-...", "type": "PagamentoRegistrado", "occurredAt": "2026-01-15T10:00:00Z" }Questões (estilo prova): escolha de padrões e implicações
1) Monólito vs microserviços
Um sistema precisa de deploys independentes por área e escalabilidade muito maior apenas no módulo de processamento. Qual estilo tende a atender melhor e qual o principal custo associado?
Em um ambiente com pouca automação e equipe reduzida, qual abordagem tende a reduzir risco operacional? Justifique com base em complexidade e observabilidade.
2) Síncrono vs assíncrono
Para uma validação que precisa bloquear a operação imediatamente (ex.: checagem obrigatória antes de confirmar), qual integração é mais adequada? Quais mecanismos de confiabilidade devem acompanhar (timeout, retry, circuit breaker)?
Para absorver picos de solicitações sem derrubar dependências, qual integração é mais adequada? Quais implicações surgem em consistência e duplicidade?
3) Filas e tópicos
Qual a diferença prática entre fila e tópico quanto ao número de consumidores que recebem a mesma mensagem?
Em qual cenário faz mais sentido publicar um evento em tópico em vez de enviar um comando em fila?
4) Garantias de entrega e idempotência
Explique por que “pelo menos uma vez” exige idempotência no consumidor e qual falha típica gera duplicidade.
Quais são duas estratégias para tornar o processamento idempotente? Cite uma baseada em
eventIde outra baseada em chave de negócio.
5) Desempenho e confiabilidade
Como a escolha por microserviços pode aumentar latência em comparação ao monólito? Cite dois fatores.
Como mensageria pode aumentar confiabilidade em picos e indisponibilidades? Qual o trade-off em termos de consistência?
6) Observabilidade e correlação
Qual a função de logs, métricas e traces, e como eles se complementam em incidentes?
Por que
correlationIdecausationIdsão importantes em fluxos assíncronos? Dê um exemplo de investigação que depende desses IDs.