Some checks are pending
CI — CoM Config Validation / Validate JSON Configs (push) Waiting to run
CI — CoM Config Validation / Validate YAML Configs (push) Waiting to run
CI — CoM Config Validation / Lint Shell Scripts (push) Waiting to run
CI — CoM Config Validation / Secret Detection (push) Waiting to run
CI — CoM Config Validation / Lint Markdown (push) Waiting to run
CI — CoM Config Validation / Validate CODEOWNERS (push) Waiting to run
Public, sanitized mirror of an AI orchestration command center: agents, skills, MCP servers, slash-command workflows. All infrastructure identifiers, hostnames, mesh IPs/subnets, repo paths, maintainer identity, and hardware fleet specifics scrubbed to <placeholders>; session debug logs and host-specific memory removed. No live credentials. Verified clean by automated leak sweep. See SANITIZATION.md. churchofmalware.org . authorized research only
4.0 KiB
4.0 KiB
DDD / Onion Layer Reference
Compact reference for layer-aware TDD. Not a DDD textbook — just enough for agents to enforce dependency direction and choose the right test strategy.
Why This Matters (Research-Backed)
- AI-generated code without architectural constraints produces 80% dependency violation rates in hexagonal architecture (arXiv:2512.04273, 2025). Layer constraints in agent prompts directly counteract this.
- Static tools detect only ~77% of dependency violations on average (Pruijt et al., 2017). Our refactorer supplements tooling by checking imports + transitive deps during code review.
- Test-driven prompting improves LLM code generation accuracy by 38-45% (Naik et al., 2024). RED-first with focused prompts is empirically better than spec-first.
- TDD alone doesn't automatically improve design (Turhan et al., 2017). The REFACTOR phase with dependency checks is essential, not optional — it's where architectural quality emerges.
Layer Definitions (Inside → Outside)
Domain Model (Core)
- Entities, Value Objects, Aggregates, Domain Events
- ZERO external dependencies (no ORM, no HTTP, no frameworks)
- Test with: direct construction, no mocks
- Example:
Userentity with email validation,Moneyvalue object with currency math
Domain Services
- Complex operations spanning multiple aggregates
- Depends on: Domain Model only (+ interfaces for ports it needs)
- Test with: real domain objects, in-memory fakes for repository interfaces
- Example:
RegistrationServicechecking uniqueness via a repository interface
Application Services (Use Cases)
- Orchestrate domain logic, handle transactions, coordinate side effects
- Depends on: Domain Model + Domain Services
- Defines port interfaces that infrastructure will implement
- Test with: in-memory fakes for all ports/repositories
- Example:
RegisterUserUseCasecoordinating validation, persistence, email notification
Infrastructure & Presentation
- DB access, external APIs, controllers, CLI handlers, adapters
- Depends on: all inner layers (implements their interfaces)
- Test with: integration tests, may use real dependencies or test containers
- Example:
PostgresUserRepositoryimplementingUserRepositoryinterface
Port Interface Placement
Ports (interfaces that abstract external dependencies) are defined by the layer that consumes them, not the layer that implements them:
- A
UserRepositoryinterface consumed by a domain service lives indomain/ports/ordomain-service/ports/ - A
NotificationServiceinterface consumed by an application use case lives inapplication/ports/ - Infrastructure implements these interfaces but never defines them
Rule: the consumer defines the contract; the provider fulfills it. This is the Dependency Inversion Principle.
Dependency Rule
Dependencies flow INWARD only. Inner layers define interfaces (ports); outer layers implement them (adapters).
Infrastructure → Application → Domain Services → Domain Model
↓ ↓ ↓ ↓
implements orchestrates uses real pure logic
interfaces via ports domain objects no imports
Violation example: domain/user.py importing from infrastructure.db import Session — domain must never import infrastructure.
Layer Detection Heuristics
When classifying a slice, ask:
- Does it involve only business rules with no I/O? → domain
- Does it coordinate multiple domain objects but still no I/O? → domain-service
- Does it orchestrate a workflow (validate, persist, notify)? → application
- Does it talk to a database, HTTP API, file system, or framework? → infrastructure
Test Strategy by Layer
| Layer | Mocks/Fakes | Framework imports | I/O allowed |
|---|---|---|---|
| domain | None | None | No |
| domain-service | In-memory fakes for ports | None | No |
| application | In-memory fakes for all ports | Minimal (DI container) | No |
| infrastructure | Optional (real deps or test containers) | Yes | Yes |