Software ArchitectureSystem Design

Clean Architecture vs Hexagonal (Ports & Adapters): The Complete Practical Guide

TT
TopicTrick Team
Clean Architecture vs Hexagonal (Ports & Adapters): The Complete Practical Guide

Clean Architecture vs Hexagonal (Ports & Adapters): The Complete Practical Guide


Table of Contents


The Problem: Dependency Creep

In most applications grown organically, the business logic is entangled with infrastructure:

typescript

The consequences:

  • Unit testing the "empty order" rule requires a real HTTP server AND a real database
  • Swapping PostgreSQL for MongoDB requires touching business logic code
  • Adding a CLI interface for admin orders would duplicate the business rules

The Dependency Inversion Principle (DIP): The Foundation

The DIP states: High-level modules should not depend on low-level modules. Both should depend on abstractions.

text

When business logic depends on an interface (not a concrete database), you can swap implementations freely. The database Adapter implements the interface — the domain defines it.


Hexagonal Architecture: Driving vs Driven Ports

Alistair Cockburn's Hexagonal Architecture divides adapters into two categories:

mermaid

Driving Ports (left side): Interfaces that the outside world uses to call your application (e.g., PlaceOrderUseCase). Driving Adapters implement the callers (REST controllers, CLI commands).

Driven Ports (right side): Interfaces that your application calls to reach infrastructure (e.g., OrderRepository, EmailService). Driven Adapters implement these (PostgreSQL implementation, SendGrid implementation).


Clean Architecture: The Concentric Circles Explained

Uncle Bob's Clean Architecture adds more specificity to the layers inside the hexagon:

text

Dependency Rule: Source code dependencies can only point inward. The inner circle knows nothing about the outer circles.

LayerContainsKnows About
Domain/EntitiesBusiness objects, domain logicNothing (pure business)
Use CasesApplication-specific business rulesOnly Domain layer
Interface AdaptersControllers, Presenters, GatewaysUse Cases + Domain
Frameworks & DriversDB, Web, UI frameworksEverything

Ports vs Adapters: Implementation in TypeScript

typescript

Testing Without Infrastructure

The payoff of this architecture is effortless testing. The use case has zero dependencies on real infrastructure:

typescript

The Directory Structure

text

Frequently Asked Questions

What's the real difference between Clean and Hexagonal Architecture? Hexagonal is focused on the boundary between the application and the outside world — it explicitly categorises Driving vs Driven ports. Clean Architecture is focused on the internal layering — it adds the Domain/Entities and Use Cases distinction inside the hexagon. In practice, most production architectures use both concepts simultaneously: Clean Architecture's layers internally, Hexagonal's Port/Adapter naming externally.

How is this different from standard Layered (N-Tier) Architecture? In standard layered architecture, the Business Layer calls the Data Access Layer — it depends downward onto database code. In Hexagonal/Clean, the Business Layer defines an interface (Port) and the database implements that interface — the dependency is inverted. This means the business layer has zero knowledge of the database.


Key Takeaway

Clean and Hexagonal Architecture solve the same problem differently (circles vs hexagon), but produce the same outcome: business logic that is completely isolated from frameworks and databases. This isolation makes testing trivial, infrastructure swapping straightforward, and long-term maintainability dramatically better. The cost is real — more interfaces, more adapters, more code. Accept that cost gladly for systems with complex business rules that will live for 5+ years. Skip it for simple CRUD applications where the database is the business logic.

Read next: Microkernel Architecture: Building a Plugin-Based System →


Part of the Software Architecture Hub — comprehensive guides from architectural foundations to advanced distributed systems patterns.