Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Architecture Decision Records (ADRs)

This directory contains Architecture Decision Records - documents that capture important architectural choices made during DaedalusOS development.

What is an ADR?

An ADR documents why a significant technical decision was made. It captures:

  • The problem or choice faced
  • Alternatives considered
  • The decision and rationale
  • Consequences and trade-offs

ADRs are lightweight (typically 100-400 lines) and focus on decision rationale, not implementation details.

When to Write an ADR

Write an ADR when:

“Would future-me wonder why this design exists?”

Specific triggers:

  • One-way doors: Hard-to-reverse decisions (e.g., target platform, no multi-arch)
  • Non-obvious trade-offs: Choices where alternatives had merit (e.g., QEMU version requirement)
  • Future-facing design: Adding abstraction/complexity now for future benefit (e.g., NetworkDevice trait)
  • Breaking conventions: Deviating from common patterns (with good reason)
  • External dependencies: Requiring specific versions/tools (e.g., QEMU 9.0+)

Don’t write ADRs for:

  • ❌ Implementation details (those go in module docs)
  • ❌ Obvious choices (e.g., “use Rust for Rust project”)
  • ❌ Easily reversible decisions (refactorings, minor API changes)
  • ❌ Temporary workarounds (comment in code is sufficient)

ADR Template

# ADR-XXX: Decision Title

**Status**: Accepted | Proposed | Deprecated | Superseded by ADR-YYY
**Date**: YYYY-MM-DD
**Decision**: One-sentence summary of the decision.

## Context

What problem are we solving? What constraints exist?
What alternatives were considered?

## Decision

What did we decide to do?
(Keep this section concise - 1-3 paragraphs)

## Rationale

Why this decision over alternatives?
- Reason 1
- Reason 2
- ...

### Alternatives Considered

**Alternative 1: [Name]**
- Pros: ...
- Cons: ...
- Why rejected: ...

**Alternative 2: [Name]**
- Pros: ...
- Cons: ...
- Why rejected: ...

## Consequences

### Positive
- Benefit 1
- Benefit 2

### Negative
- Cost 1
- Cost 2

### Neutral (optional)
- Side effect 1

## Related Decisions

- [ADR-XXX: Related Decision](adr-xxx.md) - How it relates

## References

- [External source 1](https://...)
- [External source 2](https://...)

Best Practices

1. Context Before Decision

Explain the problem and show alternatives before stating what you chose. This prevents “obvious in hindsight” bias.

Good:

## Context
We need to support multiple network devices (Pi 4 GENET, future Pi 5, QEMU mock).

Three approaches:
- A) Direct GENET usage (no abstraction)
- B) Full trait abstraction now
- C) Minimal trait now, implement later

## Decision
Chose option C: Minimal trait now...

Bad:

## Decision
We're using a trait for network devices.

## Context
This lets us support multiple devices...

2. Acknowledge Trade-offs

Good ADRs admit downsides. No decision is perfect.

Good:

### Negative
- Setup complexity: Users must build QEMU from source
- CI build time: ~4 minutes on first run

Bad:

### Consequences
- Better testing
- More accurate emulation
(No admission of downsides)

3. Status Lifecycle

Proposed → Accepted → [Deprecated | Superseded]
  • Proposed: Under discussion, not yet implemented
  • Accepted: Implemented and active
  • Deprecated: No longer recommended, but code remains
  • Superseded by ADR-XXX: Replaced by new decision

Update status when circumstances change.

Decisions often build on or conflict with previous ones:

## Related Decisions
- [ADR-001: Pi 4 Only](adr-001-pi-only.md) - Why we need raspi4b specifically
- [ADR-003: Network Abstraction](adr-003.md) - Plans for multi-device support

Numbering Convention

ADRs are numbered sequentially with zero-padding:

  • adr-001-pi-only.md
  • adr-002-qemu-9.md
  • adr-003-network-device-trait.md

Numbers are permanent. If ADR-002 is superseded, we create ADR-004 (not rename ADR-002).

File Naming

Format: adr-NNN-short-slug.md

Examples:

  • adr-001-pi-only.md
  • adr-002-qemu-9.md
  • adr-1-raspberry-pi-4-only-target-platform.md (too long, no zero-padding)

Examples in This Project

ADR-001: Raspberry Pi 4 Only

Type: Platform choice (one-way door) Demonstrates: Clear rationale for rejecting multi-platform, detailed reversal plan

ADR-002: QEMU 9.0+ Requirement

Type: External dependency requirement Demonstrates: “Why Not” alternatives section, multiple implementation options

ADR-003: Network Device Abstraction

Type: Future-facing design (abstraction for 1 implementation) Demonstrates: Three options with honest pros/cons, migration path, design pattern comparisons

ADR-004: Linux Kernel Filesystem Structure

Type: Code organization (maintainability choice) Demonstrates: Practical benefits prioritized over strict conformance, clear deviation policy

ADR-005: Multi-Board Support Strategy

Type: Future-facing architecture (multi-platform preparation) Demonstrates: Hybrid approach reasoning, four alternatives compared, deferred implementation

Anti-Patterns to Avoid

“Implementation Masquerading as ADR”

# ADR-006: UART Driver Implementation
## Decision
The UART driver uses PL011 registers at 0xFE201000...

→ This is implementation detail, belongs in module docs.

“No Alternatives Shown”

## Decision
We use Rust.

→ If there’s no real choice, don’t write an ADR.

“Bias Toward Decision”

## Alternatives
1. Direct GENET usage - terrible, inflexible, bad
2. Trait abstraction - perfect, elegant, future-proof

→ Be honest about trade-offs.

ADR Workflow

  1. Identify decision: Recognize a significant architectural choice
  2. Draft ADR: Use template, fill in context/alternatives
  3. Discuss if needed: For team projects; solo projects can skip
  4. Implement: Make the change
  5. Finalize ADR: Update with actual implementation details
  6. Commit together: ADR and implementation in same PR/commit

For DaedalusOS (solo project), ADRs can be written during or after implementation, as long as rationale is captured while fresh.

References