Files
archlens/docs/adr/0001-hexagonal-architecture-with-ddd.md
Gabriel Kaszewski 35f27d00b0
Some checks failed
CI / Check / Test (push) Failing after 1m24s
init: archlens — architecture diagram generator
Hex arch + DDD, tree-sitter parsing, Mermaid/ASCII output.
Supports Rust + Python. 92 tests. CI, diff, --check for staleness detection.
2026-06-16 16:13:04 +02:00

2.3 KiB

0001 — Hexagonal Architecture with DDD

Status: Accepted
Date: 2026-06-16

Context

Archlens is a language-agnostic architecture diagram generator. It needs to support multiple input languages (Rust, C#, Python), multiple output formats (Mermaid, ASCII, future: D2, interactive web), and multiple IO strategies (file, stdout). The tool must be extensible without modifying core logic.

Decision

Use hexagonal architecture (ports and adapters) with DDD structuring. Workspace layout:

crates/
  domain/          — zero external deps (no tracing, no rayon, nothing)
  application/     — depends on domain only + rayon, tracing (pragmatic utility exceptions)
  adapters/
    tree-sitter/   — SourceAnalyzer (internal modules per language)
    walkdir/       — FileDiscovery
    mermaid/       — DiagramRenderer
    ascii/         — DiagramRenderer
    file-writer/   — OutputWriter
    stdout-writer/ — OutputWriter
    toml-config/   — ConfigLoader
  presentation/    — CLI (clap), composition root, tracing-subscriber setup

Dependency rules:

  • Domain depends on nothing
  • Application depends on domain
  • Adapters depend on domain (not application)
  • Presentation depends on application + adapters (composition root)

Use cases are generic over port traits (static dispatch), not trait objects.

Pragmatic exceptions: rayon and tracing in application crate. These are general-purpose utilities, not external system adapters. Documented explicitly to avoid precedent creep.

Alternatives Considered

  • Trait objects for DI: Simpler type signatures but runtime dispatch overhead and less compile-time safety. Rejected — generics align better with Rust idioms and zero-cost goals.
  • DI container (shaku): Unnecessary ceremony for Rust. Manual wiring in presentation is explicit and sufficient.
  • Domain with tracing dependency: Rejected to keep domain fully pure. Application wraps domain calls in spans.

Consequences

  • Adding a new language = new module in tree-sitter adapter (or new adapter crate)
  • Adding a new output format = new adapter crate implementing DiagramRenderer
  • Adding a new output destination = new adapter crate implementing OutputWriter
  • Use case type signatures carry multiple generic parameters (accepted tradeoff)
  • Domain crate is testable with zero setup — no mocks for infrastructure needed