Skip to content

How to Write a Good ADR

This document provides a practical guide and template for writing high-quality Architecture Decision Records (ADRs) at ConnectSoft. It is written for architects, engineers, and anyone documenting technical architecture decisions.

ADRs capture important architectural choices, their context, alternatives considered, and consequences. This guide shows how to write ADRs that are clear, useful, and maintainable.

Tip

When in Doubt: If you feel you'll need to explain this decision to a new developer or partner in 3 months, it probably deserves an ADR. ADRs are for non-trivial, long-lived technical choices that affect architecture, patterns, or implementation across services.

When to Write an ADR

Write an ADR When:

  • Architecture Direction Changes - New patterns, core frameworks, or architectural principles are introduced
  • Significant Technology Choice - Choosing event bus, ORM, hosting model, observability stack, or similar foundational tech
  • Cross-Cutting Patterns - Defining tenancy model, authentication approach, logging standards, or error handling patterns
  • Template or Library Decisions - Major choices about templates, libraries, or shared components
  • Integration Patterns - How services integrate with each other or external systems

Do NOT Write an ADR For:

  • Minor implementation details in a single service
  • Temporary workarounds or quick fixes
  • Choices that are clearly documented elsewhere (e.g., in templates)
  • Day-to-day operational tweaks

See: Decisions Overview and Process for when to use ADR vs BDR.

ADR Structure and Template

Standard ADR Template

Use this template for all new ADRs:

# ADR-XXXX – Title

- **Status:** Proposed | Accepted | Superseded | Rejected
- **Date:** YYYY-MM-DD
- **Deciders:** <names/roles>
- **Supersedes:** <ADR-XXXX> (optional)
- **Superseded by:** <ADR-XXXX> (optional)

## Context

<What problem are we solving? Why now? What constraints?>

## Decision

<What choice did we make? State it clearly and unambiguously.>

## Consequences

### Positive

- ...

### Negative / Trade-offs

- ...

## Alternatives Considered

- **Option A** – Pros/Cons
- **Option B** – Pros/Cons

## References

- Links to docs, issues, POCs
- Related ADRs/BDRs
- Architecture docs

Template Sections Explained

Header Metadata:

  • Status - Current state of the decision (MUST be present)
  • Date - When decision was made or proposed
  • Deciders - Who made the decision (Dmitry, architect, team)
  • Supersedes/Superseded by - Links to related decisions

Context:

  • What problem are we solving?
  • Why is this decision needed now?
  • What constraints or requirements exist?
  • What is the scope (all services, specific platform, etc.)?

Decision:

  • Clear, unambiguous statement of the choice
  • Should be understandable in 1–2 sentences
  • Avoid vague language

Consequences:

  • Positive outcomes and benefits
  • Negative outcomes, trade-offs, and risks
  • Implementation implications

Alternatives Considered:

  • What other options were evaluated?
  • Why were they not chosen?
  • What are the trade-offs?

References:

  • Links to related docs, issues, POCs
  • Related ADRs or BDRs
  • Architecture documentation

See: ADR Index for examples of existing ADRs.

Content Guidelines

Writing Rules

One Main Decision Per ADR:

  • Avoid mixing unrelated decisions
  • If multiple related decisions, consider separate ADRs with cross-references
  • Keep focus clear and scoped

Clear Decision Statement:

  • The Decision section should be understandable in 1–2 sentences
  • Avoid vague language like "we might... maybe... somehow"
  • Be explicit: "We will use X" not "We should consider X"

Specific Context:

  • What project, domain, or platform does this apply to?
  • What constraints or requirements drive this decision?
  • Why is this decision needed now?

Honest About Trade-offs:

  • Document both positive and negative consequences
  • Acknowledge limitations and risks
  • Help future readers understand the full picture

Important

Avoid Vague Language: ADRs MUST avoid vague language like "we might... maybe... somehow." State decisions clearly and unambiguously. The Decision section should be understandable in 1–2 sentences.

Example: ADR-0001 (Annotated)

ADR-0001 (Use log4brains for Architecture Decision Records) demonstrates good ADR structure:

Pattern:

  • Clear Scope - Decision about documentation tooling, affects all ADRs
  • Explicit Decision - "We will use log4brains for managing ADRs"
  • Specific Context - Why we need ADR tooling, what alternatives exist
  • Honest Trade-offs - Benefits and limitations of log4brains

Annotated Mini-Example:

# ADR-0001 – Use MassTransit with RabbitMQ for Service Messaging

- **Status:** Accepted
- **Date:** 2024-XX-XX
- **Deciders:** Dmitry (Chief Architect)

## Context

ConnectSoft microservices need reliable, scalable messaging for event-driven architecture.
We evaluated multiple message bus options considering: .NET integration, cloud hosting,
multi-tenancy support, and operational complexity.

## Decision

We will use MassTransit with RabbitMQ as the default message bus for ConnectSoft microservices.
All Factory-generated services will use MassTransit abstractions, with RabbitMQ as the
default broker. Services may use other brokers (Azure Service Bus) if needed, but must
use MassTransit abstractions.

## Consequences

### Positive

- Strong .NET integration and developer experience
- Abstraction layer allows broker switching
- Good multi-tenancy support
- Active community and documentation

### Negative / Trade-offs

- RabbitMQ requires operational expertise
- Additional infrastructure dependency
- Learning curve for team members new to MassTransit

## Alternatives Considered

- **Azure Service Bus** – Pros: Managed service, good Azure integration. Cons: Vendor lock-in, cost at scale
- **NATS** – Pros: Lightweight, fast. Cons: Less .NET ecosystem support, different patterns
- **Direct HTTP** – Pros: Simple, no infrastructure. Cons: Not suitable for async, no guarantees

## References

- [Event-Driven Mindset](../architecture/event-driven-mindset.md) - Event patterns
- [Factory Overview](../factory/overview.md) - Factory architecture
- MassTransit Documentation: https://masstransit.io

Why This Is a Good ADR:

  • Clear Scope - Applies to all microservices, Factory-generated code
  • Explicit Decision - "We will use MassTransit with RabbitMQ"
  • Specific Context - Why messaging is needed, what was evaluated
  • Honest Trade-offs - Both benefits and limitations documented
  • Alternatives Documented - Shows other options were considered
  • References - Links to related architecture docs

Review and Maintenance

Review Process

Initial Review: 1. Draft ADR with status "Proposed" 1. Share with relevant stakeholders (Dmitry, architects, team) 1. Gather feedback and refine 1. Update status to "Accepted" when finalized

Periodic Review:

  • Major platform/Factory ADRs should be reviewed periodically
  • Check if decisions are still relevant
  • Update status if decision is superseded or deprecated

Maintenance Rules

Updating ADRs:

  • Don't Edit History - Don't change accepted decisions retroactively
  • Create New ADR for Changes - If decision changes, create new ADR and mark old as "Superseded"
  • Fix Typos Only - Minor clarifications are OK if clearly marked
  • Link Superseded Decisions - Always link old and new decisions

Supersession Process:

  1. Create new ADR with updated decision
  2. Link to old ADR: "Supersedes: ADR-XXXX"
  3. Update old ADR status to "Superseded"
  4. Link old ADR to new: "Superseded by: ADR-YYYY"
  5. Update indexes to reflect new status

Warning

Don't Edit History: Avoid editing old ADRs in ways that hide history. Only fix typos or add clarifications clearly marked. If a decision changes, create a new ADR and mark the old one as "Superseded" with proper linking.

Status Management

Status Transitions:

  • Proposed → Accepted - Decision is finalized
  • Accepted → Superseded - Decision is replaced by new ADR
  • Accepted → Rejected - Decision is explicitly not chosen (rare)
  • Any → Superseded - New decision replaces old one

See: Decisions Overview and Process for status definitions.