Template de ADR e exemplos: formatos prontos para copiar

A reunião já durava duas horas. Estávamos debatendo se usaríamos PostgreSQL ou MongoDB em um novo serviço. Os argumentos iam e voltavam: integridade relacional, schemas flexíveis, familiaridade da equipe, complexidade operacional.

Então alguém comentou: "A gente não teve exatamente essa discussão no ano passado, para o user service?"

Silêncio. Tínhamos tido. Um ano antes, passamos o mesmo tempo na mesma pergunta e escolhemos PostgreSQL. Ninguém lembrava do raciocínio, e o engenheiro que conduziu aquela discussão tinha saído da empresa. Então estávamos refazendo o mesmo debate do zero.

Foi aí que começamos a escrever Architecture Decision Records. Este post é a parte de copiar e colar: três templates, quando usar cada um e três das nossas próprias decisões preenchidas.

O que é um ADR?

Um architecture decision record é um documento curto que registra uma única decisão de arquitetura. Não é um documento de design que cobre tudo sobre um sistema, apenas uma decisão:

  • O que decidimos
  • Por que decidimos
  • Quais alternativas consideramos
  • Quais são as consequências

Um ADR deve caber em uma ou duas páginas. Se ficar mais longo, provavelmente você está documentando mais de uma decisão. O guia completo cobre quando escrever um, o ciclo de vida e os erros que as equipes cometem; este post fica nos formatos.

O template mínimo (Nygard)

Michael Nygard propôs o formato que a maioria das equipes ainda usa em um post de 2011. Cinco partes: um título que é uma frase nominal curta, um status, o contexto ("as forças em jogo"), a decisão ("nossa resposta a essas forças") e as consequências ("o contexto resultante, depois de aplicar a decisão"). Os status dele são Proposed, Accepted, Deprecated e Superseded.

# ADR-NNNN: Frase nominal curta

## Status

Proposed | Accepted | Deprecated | Superseded by ADR-XXXX

## Context

Que forças estão em jogo? Técnicas, organizacionais, prazo, orçamento.
Seja específico: números, restrições, quem é afetado.

## Decision

Vamos ...

## Consequences

O que fica mais fácil, o que fica mais difícil, o que agora precisamos vigiar.

Nós acrescentamos uma seção: Alternatives Considered, entre Decision e Consequences. É a parte que mais economiza tempo depois, porque a pergunta que aparece um ano mais tarde raramente é "o que escolhemos?" e quase sempre "por que não escolhemos X?"

## Alternatives Considered

### Opção B
- Prós: ...
- Contras: ...
- Por que foi rejeitada: ...

MADR

O MADR (Markdown Architectural Decision Records) é um template mais estruturado, mantido em adr.github.io/madr. A versão atual é a 4.0.0, lançada em 17 de setembro de 2024. Ele coloca os metadados no frontmatter YAML e transforma as opções e seus trade-offs em seções explícitas em vez de texto corrido.

---
status: proposed | rejected | accepted | deprecated | superseded by ADR-XXXX
date: AAAA-MM-DD
decision-makers: ...
consulted: ...
informed: ...
---

# Título curto do problema resolvido e da solução escolhida

## Context and Problem Statement

Duas ou três frases, ou uma história curta. De preferência formulado como uma pergunta.

## Decision Drivers

* Driver 1
* Driver 2

## Considered Options

* Opção A
* Opção B
* Opção C

## Decision Outcome

Opção escolhida: "Opção A", porque ...

### Consequences

* Bom, porque ...
* Ruim, porque ...

### Confirmation

Como vamos verificar que a decisão foi implementada (revisão, teste, fitness function).

## Pros and Cons of the Options

### Opção A

* Bom, porque ...
* Ruim, porque ...

## More Information

Links, decisões relacionadas, quando revisitar.

No MADR, toda seção depois de Considered Options e Decision Outcome é opcional. Apague o que não usar em vez de deixar títulos vazios.

Y-statement

O Y-statement cabe uma decisão em uma única frase. Ele vem de Uwe Zdun, Olaf Zimmermann e colegas ("Sustainable Architectural Design Decisions", IEEE Software, 2013):

No contexto de <caso de uso ou componente>,
diante de <preocupação ou requisito>,
decidimos por <opção>
(e contra <outras opções>),
para alcançar <qualidade ou benefício>,
aceitando que <desvantagem>.

É curto demais para carregar uma seção de contexto completa, e esse é justamente o ponto. Use para decisões que não merecem uma página, como linha de resumo no topo de um ADR mais longo ou como formato das entradas de um log de decisões.

Qual formato usar

Formato Use quando Cuidado com
Nygard (mais alternativas) Você está começando, ou a maioria das decisões tem um vencedor óbvio e algumas opções rejeitadas Seções de contexto que viram redações
MADR As decisões são disputadas, várias pessoas precisam aprovar, ou você quer opções e drivers comparáveis entre ADRs Preencher todas as seções opcionais por hábito
Y-statement Decisões pequenas, um log de decisões ou um resumo de uma linha no topo de um ADR mais longo Usá-lo em decisões que precisam de uma seção de contexto de verdade

Escolha um para o repositório e mantenha. Formatos misturados são mais difíceis de ler do que qualquer formato único é de escrever.

Exemplo 1: ADR-0042, PostgreSQL para o Order Service

Esta é a decisão da história do início, no formato Nygard com a nossa seção Alternatives Considered.

# ADR-0042: Usar PostgreSQL no Order Service

## Status

Accepted

## Context

O order service precisa de armazenamento persistente para os dados de pedidos.
Esperamos processar 50.000 pedidos por dia no início, chegando a 500.000
em dois anos. Os pedidos têm uma estrutura bem definida, mas podem precisar
de campos de metadados adicionais ao longo do tempo. A equipe tem experiência
com bancos relacionais e com bancos de documentos.

## Decision

Vamos usar o PostgreSQL 15 como banco de dados principal do order service.

Escolhemos o PostgreSQL porque:

- Conformidade ACID é obrigatória para dados financeiros de pedidos
- Colunas JSON dão flexibilidade de schema para os metadados
- Nossa equipe de infraestrutura tem experiência operacional com PostgreSQL
- Os padrões de consulta se encaixam bem na modelagem relacional

## Alternatives Considered

### MongoDB

- Prós: armazenamento JSON nativo, escalabilidade horizontal mais simples, evolução flexível do schema
- Contras: garantias de consistência mais fracas, equipe menos familiarizada com a operação,
  exigiria ferramentas adicionais para transações

### DynamoDB

- Prós: totalmente gerenciado, operação mínima, escalabilidade excelente
- Contras: lock-in na AWS, padrões de consulta limitados ao acesso por partition/sort
  key, custo imprevisível em alta escala

## Consequences

### Positive

- Garantias fortes de integridade dos dados
- A equipe pode reaproveitar a experiência que já tem com PostgreSQL
- Características operacionais bem conhecidas

### Negative

- Migrações de schema exigem mais planejamento do que em bancos de documentos
- Escalabilidade horizontal mais complexa se ultrapassarmos a capacidade de um nó
- Precisaremos de sharding na aplicação se chegarmos aos limites de escala

### Risks

- Pode ser preciso revisitar se o volume passar de 1M de pedidos por dia
- Consultas em colunas JSON são menos eficientes do que em bancos de documentos nativos

## Related Decisions

- Veja o ADR-0007 para entender por que aceitamos consistência eventual
- Substitui o ADR-0003, que recomendava MongoDB

Seja específico no contexto. "Precisamos de conformidade ACID" ajuda o próximo leitor muito mais do que "precisamos de confiabilidade". E seja honesto nas consequências: nenhuma decisão é de graça, e registrar as desvantagens diz às equipes futuras quando é hora de revisitar.

Exemplo 2: ADR-0007, comunicação orientada a eventos, em MADR

A decisão sobre o Kafka tinha mais opções na mesa e mais pessoas envolvidas, e é aí que os drivers e opções explícitos do MADR justificam o espaço que ocupam.

---
status: accepted
---

# Usar Kafka para comunicação assíncrona entre serviços

## Context and Problem Statement

Nossos microsserviços se comunicam de forma síncrona via HTTP. Isso os acopla
fortemente, e um serviço indisponível vira uma cascata de falhas mais acima.
Como os serviços devem se comunicar quando quem chama não precisa
de uma resposta imediata?

## Decision Drivers

* Resiliência: um serviço fora do ar não pode derrubar os outros
* Acoplamento mais fraco entre os serviços

## Considered Options

* Manter HTTP síncrono
* Comunicação orientada a eventos com Apache Kafka

## Decision Outcome

Opção escolhida: "Comunicação orientada a eventos com Apache Kafka", porque
remove o acoplamento em tempo de execução que causa as falhas em cascata.

### Consequences

* Bom, porque os serviços ficam mais resilientes às falhas uns dos outros
* Ruim, porque passamos de consistência forte para consistência eventual
* Ruim, porque agora operamos um cluster Kafka
* Ruim, porque a equipe precisa de treinamento em padrões orientados a eventos

O status e o título se mantêm; os campos date e decision-makers ficaram de fora aqui porque o registro original não os guardava.

Exemplo 3: ADR-0015, um monorepo de frontend, como Y-statement

A decisão do monorepo cabe em uma frase, e a frase basta para responder "por que está tudo em um repositório só?"

No contexto das nossas 5 aplicações de frontend em repositórios separados,
diante de versões desalinhadas e do custo de publicar pacotes para compartilhar código,
decidimos por um único monorepo gerenciado com Nx
(e contra repositórios separados com um gerenciamento de pacotes melhor, e contra um monorepo sem Nx),
para alcançar um compartilhamento de código simples e um único pull request que atualiza o código compartilhado e todos os seus consumidores,
aceitando que um repositório maior precisa de cache de build e que as aplicações podem se acoplar sem querer.

As opções rejeitadas têm suas razões no registro completo: os repositórios separados mantinham o custo de coordenação, e um monorepo sem Nx teria tornado os tempos de build proibitivos.

Onde guardá-los

Coloque os ADRs no repositório que eles descrevem, em docs/adr/ ou docs/decisions/ (Nygard sugeria doc/arch/adr-NNN.md). Eles são versionados com o código, aparecem no code review e não se perdem em um wiki.

Numere-os em sequência e nunca reutilize um número. Quando uma decisão mudar, escreva um novo ADR que substitui o antigo e atualize o status do antigo, em vez de editar a história.

O passo que a maioria das equipes pula é ligar um ADR à parte do sistema que ele afeta. No Archyl, um ADR tem os campos de Nygard (status, contexto, decisão, consequências), mais uma data e um link "substituído por", e se liga aos sistemas, containers e componentes que ele moldou. Qualquer pessoa que olhe o order service no diagrama C4 vê o ADR-0042 ao lado: "Por que este serviço usa PostgreSQL?" está a um clique.

As armadilhas (escrever ADRs depois do fato, deixá-los chegar a cinco páginas, abandonar a prática depois do primeiro trimestre corrido) estão no guia completo.

Comece com um

Aquela reunião de duas horas sobre PostgreSQL vs MongoDB? Na vez seguinte em que a pergunta apareceu, ela terminou em dez minutos, porque alguém encontrou o ADR-0042. As restrições, as alternativas e o raciocínio estavam todos lá. Confirmamos que a decisão original ainda valia e seguimos em frente.

Escolha um dos templates acima e cole em docs/adr/0001-record-architecture-decisions.md. Seu primeiro ADR pode ser a decisão de escrever ADRs.


Saiba mais sobre documentação de arquitetura: o guia do modelo C4 | Por que a documentação importa | Documentando fluxos de usuário