Hexagonal Architecture with DDD
Context
ResearchOS manages complex research objects — Experiments, Runs, Notebooks, Papers, Datasets, Models, Artifacts — each with rich business logic. The system must remain testable and allow replacing databases, AI providers, and APIs without modifying core logic.
What I considered
- MVC with Fat Services — rejected: business logic leaks into services, hard to test independently
- Microservices — rejected: operational complexity outweighs benefits for the current scale
- Hexagonal Architecture with DDD — selected: business logic isolated in domain layer, infrastructure behind interfaces
What I chose
Use Domain-Driven Design with Hexagonal Architecture (Ports and Adapters). Each research object is an Aggregate Root. Business logic lives in the domain layer. Infrastructure implements interfaces defined by the domain. Dependency direction: API → Application → Domain. Infrastructure depends on domain, never the reverse.
Trade-offs
- +Replace databases, AI providers, and APIs without modifying business logic
- +Domain logic is fully testable without infrastructure
- +Clear bounded contexts prevent coupling between research modules
- −More files and indirection than a simple MVC approach
- −Team must understand DDD patterns to contribute effectively
- −Interface definitions require upfront design investment
What I would do differently
The upfront cost of Hexagonal Architecture is real but pays off within weeks. When we needed to swap embedding providers, it was a single adapter change with zero domain code touched.