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.