Trabalho Por Equipe DevBras

Capa do artigo: ADR na prática: registre a decisão de arquitetura e a alternativa que perdeu

ADR na prática: registre a decisão de arquitetura e a alternativa que perdeu

Um modelo curto de registro de decisão (contexto, decisão, alternativas, consequências) guardado no repositório, para o time não refazer o mesmo debate daqui a seis meses.

Reunião de planejamento, março. Alguém propõe trocar a fila de e-mails do PostgreSQL para o Redis, "porque é o padrão". Metade do time concorda. Ninguém lembra que isso foi discutido em setembro, que o Redis foi rejeitado porque a hospedagem não oferecia persistência confiável e que a decisão economizou um serviço inteiro para manter. A pessoa que sabia disso saiu em dezembro. A decisão ficou; o porquê foi embora com ela.

A resposta curta: escreva cada decisão de arquitetura relevante numa página curta dentro do repositório, com o problema, a decisão, as alternativas rejeitadas e o motivo, data e autor. Esse formato tem nome, ADR (Architecture Decision Record), e não precisa de ferramenta. Quando a decisão mudar, não apague a antiga: marque como substituída e aponte para a nova.

Por que o porquê some

Decisões são tomadas em reunião, em chamada, em thread de chat. O resultado aparece no código; o raciocínio, não. Código mostra que a fila é uma tabela no banco. Não mostra que vocês mediram o volume (cerca de 2 mil e-mails por dia), compararam com o custo de operar outro serviço e concluíram que uma tabela bastava até 50 mil por dia.

Sem esse registro, acontecem duas coisas ruins. Ou o time refaz o debate do zero, com menos informação do que da primeira vez. Ou alguém muda a decisão sem saber da restrição que a motivou, e descobre a restrição em produção. A alternativa rejeitada é a parte mais valiosa do documento, justamente porque é a que mais se perde.

O que entra num registro de decisão

O formato mais difundido foi proposto por Michael Nygard e tem cinco partes. Variações existem (o site adr.github.io reúne várias), mas este núcleo resolve a maioria dos casos:

  • Título: a decisão em uma frase, numerada. "0007. Fila de e-mails em tabela do PostgreSQL."
  • Status: proposta, aceita, rejeitada, substituída por outra.
  • Contexto: o problema e as restrições, com números quando houver. O que força uma decisão agora.
  • Decisão: o que foi escolhido, em voz ativa. "Vamos usar..."
  • Consequências: o que fica mais fácil, o que fica mais difícil, o que precisa ser vigiado.

Na prática, vale acrescentar uma seção explícita de alternativas consideradas, cada uma com o motivo da rejeição. É ela que responde à pergunta de março.

Como começar no seu repositório, passo a passo

  1. Crie a pasta docs/adr/ na raiz do repositório.
  2. Escreva o registro zero: "0000. Vamos registrar decisões de arquitetura", explicando o formato e quando usar.
  3. Numere em sequência e use o título no nome do arquivo: 0007-fila-de-emails-no-postgres.md.
  4. Abra cada registro como pull request, para o time comentar antes de marcar como aceito.
  5. Linke o registro no pull request que implementa a decisão, e vice-versa.
  6. Quando a decisão mudar, crie um registro novo e edite apenas o status do antigo: "Substituída por 0012".

Exemplo completo

# 0007. Fila de e-mails em tabela do PostgreSQL

Status: Aceita
Data: 2026-09-14
Autoria: Renata Lima, com revisão de Diego e Paula

## Contexto

O sistema envia e-mails de confirmação e lembrete de consulta.
Hoje o envio é síncrono na requisição e falha quando o provedor
de SMTP demora. Volume atual: cerca de 2 mil e-mails por dia,
com pico de 300 por hora às segundas de manhã.
Nossa hospedagem não oferece Redis gerenciado com persistência,
e o time tem duas pessoas para cuidar da infraestrutura.

## Decisão

Vamos usar uma tabela email_fila no PostgreSQL que já operamos,
com um worker que busca lotes usando SELECT ... FOR UPDATE SKIP LOCKED.

## Alternativas consideradas

- Redis com fila em lista: rejeitado. Exigiria operar e fazer
  backup de um serviço novo, sem persistência gerenciada.
- Serviço de fila gerenciado do provedor de nuvem: rejeitado por
  ora. Resolve o problema, mas adiciona custo fixo e outra
  credencial para um volume que o banco atual comporta.
- Manter síncrono com retry na requisição: rejeitado. O usuário
  continuaria esperando o SMTP responder.

## Consequências

- Sem serviço novo para operar; backup já coberto pelo do banco.
- O banco recebe carga extra de consultas do worker; medir.
- Reavaliar se o volume passar de 50 mil e-mails por dia ou se a
  tabela começar a disputar locks com o restante do sistema.

Uma página. Quinze minutos para escrever. E responde, em março, a pergunta "por que não Redis?" com o número e a restrição que valiam em setembro. Se a hospedagem passou a oferecer Redis gerenciado, ótimo: agora o time sabe exatamente qual premissa mudou e pode escrever o registro 0012 com base nisso.

Quando vale escrever (e quando não vale)

Nem toda escolha merece registro. Nome de variável, biblioteca de data, ordem de colunas na tela: não. Um bom critério é perguntar se a decisão é cara de desfazer ou se alguém de fora provavelmente vai questioná-la. Exemplos que costumam merecer:

  • Banco de dados, fila, cache e onde cada dado mora.
  • Forma de autenticação e de autorização.
  • Monólito ou serviços separados, e onde fica a fronteira.
  • Estratégia de deploy e de migração de esquema (por exemplo, migração em dois passos).
  • Qualquer coisa em que vocês escolheram o caminho "fora do padrão" de propósito.

Existem ferramentas de linha de comando para gerar o arquivo a partir de um modelo, mas elas são opcionais. O que importa é o arquivo no repositório, versionado junto com o código que ele explica, e não numa wiki que ninguém atualiza.

Como o registro conversa com o resto do time

O registro funciona melhor quando aparece onde as pessoas já olham. Linke a pasta docs/adr/ na seção de próximos passos do README. Em revisão de código, quando um pull request contraria um registro aceito, a pergunta deixa de ser "eu acho que" e vira "o contexto do 0007 mudou?". Isso também ajuda em pull requests pequenos: a discussão grande já aconteceu no registro, e a revisão foca no código.

Depois de um incidente, vale conferir se alguma decisão registrada contribuiu para ele. O relatório de incidente sem culpa pode terminar com "revisar o ADR 0007", que é muito mais útil do que "ter mais cuidado".

Erros comuns

  • Registrar só a escolha. Sem as alternativas rejeitadas, o documento não responde à pergunta que vai aparecer, e o debate recomeça igual.
  • Apagar ou reescrever o registro antigo. Some o histórico de por que o time pensava diferente, e com ele a lição sobre qual premissa mudou.
  • Contexto sem números. "Volume baixo" não permite saber quando a decisão expira; "2 mil por dia, reavaliar em 50 mil" permite.
  • Guardar fora do repositório. A wiki desatualiza e se perde na troca de ferramenta; o arquivo junto do código sobrevive e entra na revisão.
  • Escrever um documento de dez páginas. Ninguém lê nem revisa, e o hábito morre no terceiro registro.
  • Registrar depois de implementado, meses depois. A memória já reescreveu o motivo, e as alternativas viram caricatura.

Checklist

  • Existe uma pasta de registros de decisão versionada no repositório.
  • Cada registro tem número, data, autoria e status.
  • O contexto inclui as restrições e números que motivaram a decisão.
  • As alternativas rejeitadas aparecem com o motivo de cada uma.
  • As consequências dizem o que vigiar e quando reavaliar.
  • Registros substituídos continuam no repositório, apontando para o novo.
  • O README linka a pasta de decisões.

Pense na última decisão grande do seu time: ela está escrita num arquivo que alguém que entrou ontem consegue achar, ou só existe na cabeça de quem estava na reunião?

Avalie este artigo

Referência: https://adr.github.io/