Master Hexagonal Architecture in Rust

What “hexagonal architecture” means

  • Generally described as “functional core, imperative shell”: core domain logic isolated from I/O and infrastructure.
  • Related to domain-driven design, onion architecture, and “pure vs impure” separation: pure, testable core; thin, impure adapters for HTTP, DB, FS, clock, etc.
  • Ports and adapters are defined in terms of business use cases (e.g., UserFetcher, PurchasesFetcher), not specific technologies.

Perceived benefits

  • Makes the domain independent of UI, database, and transport, so logic is clearer and more testable.
  • Enables swapping adapters for tests (DB → in‑memory store, Postgres → SQLite, HTTP → CLI) without changing core logic.
  • Helps avoid domain code depending directly on low-level concerns like SQL connections.
  • Some see it as a natural fit with functional design, pure functions, and property testing.

Critiques and skepticism

  • Many view it as over‑engineering, Java/C#‑style “enterprise” patterns imported into Rust.
  • Complaints about excessive indirection, boilerplate, and “where is the actual behavior?” debugging pain.
  • Several argue that database or HTTP server swaps almost never happen; when they do, performance, semantics, and schema changes dominate, not call‑site refactors.
  • Concerns that abstractions leak, ossify implementations, and impede performance and simple JOIN-heavy or streaming queries.

Testing and dependency injection

  • Supporters emphasize decoupling to enable fast unit/integration tests without heavy DB setup.
  • Skeptics prefer end‑to‑end tests with real databases (e.g., containers) and see DB fakes as misleading and brittle.
  • Debate over DI frameworks vs. simple constructor/trait injection; some miss Go‑style simplicity, others want better Rust DI tooling.

Rust‑specific perspectives

  • Some say the “bad” example mirrors idiomatic Axum and is fine for many APIs.
  • Others warn that heavy abstraction fights Rust’s ownership/lifetime model and costs performance, pushing everything into heap‑allocated, loosely typed layers.
  • Overall theme: start simple, let real complexity justify architecture; hexagonal patterns are useful in some contexts but harmful when applied preemptively.