Clean Architecture in Practice: A Guide for Product Engineering Teams
Clean Architecture is often taught as a diagram of concentric circles. Product teams need something sharper: a dependency rule they can enforce in CI, a place for business rules that does not depend on frameworks, and enough structure to change databases or UIs without rewriting the company.
This guide is for senior engineers, tech leads, and CTOs who want architecture that ships features—not conference slides. Related reading: microservices vs modular monolith and platform engineering for delivery speed.
The dependency rule in one sentence
Source code dependencies must point inward: outer layers (web, database, message buses, third-party SDKs) may depend on inner layers (domain and application use cases). Inner layers must not know about outer ones.
If your domain package imports Express, NestJS, Spring annotations, or Prisma types, the rule is already broken—regardless of folder names.
Four layers that work for mid-size products
- Domain — entities, value objects, domain services, invariants. No HTTP, no SQL, no cloud SDKs.
- Application — use cases / application services, ports (interfaces), orchestration, transactions at the use-case boundary.
- Adapters (interface) — controllers, GraphQL resolvers, CLI, workers that translate outside world → application commands.
- Infrastructure — repositories, email, queues, object storage, AI model clients implementing ports.
Hexagonal Architecture (“ports and adapters”) is the same idea with different vocabulary. Clean Architecture popularized the naming; the win is the boundary discipline.
Folder structure that survives growth
src/
domain/
order/
Order.ts
OrderId.ts
Money.ts
application/
place-order/
PlaceOrder.ts
PlaceOrderPort.ts
adapters/
http/
PlaceOrderController.ts
persistence/
OrderRepositoryPrisma.ts
main/
compose.ts # wiring / DI
Prefer packaging by feature or bounded context over packaging only by technical layer once you pass ~10 engineers. Hybrid models work: domain + application per context, shared kernel kept tiny.
Use cases beat “fat controllers” and “god services”
A use case should answer one business question: place order, refund payment, invite member. It:
- Accepts a command/DTO from an adapter
- Loads aggregates through ports
- Applies domain rules
- Persists and emits domain events
- Returns a result the UI can map
Keep controllers dumb. Keep domain free of framework lifecycle hooks.
When Clean Architecture is overkill
- Prototypes and throwaway spikes (time-box architecture debt)
- CRUD admin tools with almost no domain rules
- Teams under ~5 people still hunting product-market fit—use a modular monolith with clear modules first
Architecture is a product investment. Optimize for the next 12–24 months of change, not imaginary infinite scale.
Testing seams you get for free
With ports, you can unit-test use cases with in-memory repositories and fake clocks. Save expensive E2E for critical paths. Contract tests protect adapter boundaries when you extract a service later—see our companion piece on testing strategy.
Enforcement checklist
- Lint/import rules: domain cannot import adapters or infrastructure
- Architecture tests (e.g. dependency-cruiser, ArchUnit, NetArchTest)
- Code review rubric: “Where does this business rule live?”
- One composition root—no service locator spaghetti in random files
Frequently asked questions
Is Clean Architecture the same as DDD?
No. Clean Architecture organizes dependencies. Domain-Driven Design models the business. They pair well but solve different problems.
Do we need a full hexagonal setup on day one?
No. Start with domain + application modules and strict import rules. Add ports when you need multiple adapters or heavy testing isolation.
How can Auroviq help?
We audit codebases, introduce enforceable module boundaries, and coach teams while shipping product—architecture as delivery, not a rewrite holiday.
Work with Auroviq
Auroviq (AuroviQ) is a custom software and AI engineering agency based in Ahmedabad and Bhubaneswar, India, serving product companies in the UK, Netherlands, Singapore, and the US. We design architectures, ship production systems, and embed dedicated engineering teams.
Work with Auroviq — custom software & AI for product teams.