Skip to main content

> hexagonal_architecture:_ports_&_adapters_for_pure_domain_logic

Hexagonal Architecture: Ports & Adapters for Pure Domain Logic

Why do frameworks, ORMs, and third-party APIs inevitably pollute core business rules in layered architectures, and how do Hexagonal Ports and Adapters enforce complete framework independence?

Senior (L5)

THE SHORT ANSWER

In traditional 3-tier architectures (Controller -> Service -> Repository), business logic is almost always infected by framework and database concerns: domain classes inherit from ORM base entities (e.g. `@Entity` annotations in JPA or TypeORM), service methods take HTTP `Request` objects, and swapping an SQL database for DynamoDB requires rewriting the entire service layer. **Hexagonal Architecture (Ports and Adapters)**, invented by Alistair Cockburn, solves this by placing the **Domain Model at the center of a hexagon**, surrounded by two architectural concepts: (1) **Ports** (inward/outward interfaces defined *by* the domain in pure language types, e.g. `OrderRepositoryPort`, `PaymentGatewayPort`), and (2) **Adapters** (infrastructure implementations that translate between external tech and domain ports, e.g. `PostgresOrderAdapter`, `StripePaymentAdapter`, `ExpressHttpAdapter`). The domain has **zero dependencies on frameworks, databases, or UI libraries**, enabling lightning-fast unit testing without mocks, containers, or running databases.

Engineering Handbook & Failure Dynamics

1. Underlying Mechanism

Hexagonal Architecture operates on strict Dependency Inversion: (1) Driver / Inbound Ports: Interfaces that define what the application can do (e.g. `CreateOrderUseCase`). Driver Adapters (REST API, GraphQL, CLI) call these ports. (2) Driven / Outbound Ports: Interfaces that define what the application needs from the outside world (e.g. `NotificationPort`, `OrderPersistencePort`). (3) Driven Adapters: External implementations (SendGrid email adapter, Postgres SQL adapter) implement these driven ports. (4) Pure Core: The core domain entities and use cases contain 100% pure business logic with 0 framework imports.

2. Appropriate Use Context

Core banking engines, insurance policy pricing calculators, e-commerce checkout cores, and long-lived enterprise applications expected to survive multiple framework migrations.

3. Production Failure Modes

Leaking ORM entity classes directly into the domain core through driven ports, coupling domain entities to database column types; creating overly complex ports for trivial CRUD operations, introducing unnecessary boilerplate on simple forms.

4. Diagnostic Signals & Telemetry

Domain entity files importing `@nestjs/common`, `typeorm`, `express`, or AWS SDKs; unit tests requiring Docker containers or in-memory SQLite just to verify a simple business discount formula.

5. Prevention & Safeguards

Enforce the Dependency Rule via linter/fitness functions (`eslint-plugin-boundaries`): dependencies can ONLY point inwards toward the core; map database rows to pure domain entities inside the repository adapter.

6. Architectural Trade-offs

Hexagonal Architecture delivers supreme testability and total framework decoupling, but requires data mapping layers (mappers/DTOs) between database models and domain entities.

Case Study (TinyCTO In-Field Example)

A loan approval SaaS had their risk calculation algorithm tightly coupled inside a legacy MongoDB Mongoose service. When migrating to PostgreSQL for ACID compliance, rewriting the service broke the loan pricing logic. The team refactored to Hexagonal Architecture: they extracted the risk logic into a pure TypeScript `LoanEvaluator` domain class. They created a `LoanRepositoryPort` interface and two adapters: `MongoLoanAdapter` and `PostgresLoanAdapter`. They ran both adapters in parallel in production, verifying 100% calculation parity across 10,000 loans before switching traffic to Postgres with zero business logic regression.

Interactive Concept Drills

2 Cards
Q1

What is the primary difference between a Port and an Adapter in Hexagonal Architecture?

A Port is an abstract interface defined by the domain specifying what it can do or what it needs; an Adapter is the concrete technology implementation connecting external tools to that port.
Q2

Why does Hexagonal Architecture make domain unit testing faster and easier?

Because the domain core has zero framework or database dependencies, allowing tests to run in-memory with simple in-memory mock adapters without starting servers or databases.

Hexagonal Architecture: Ports & Adapters for Pure Domain Logic — Technical FAQ

Is Clean Architecture the same as Hexagonal Architecture?

They share the exact same core principle (Dependency Inversion with pure domain at the center). Clean Architecture (Uncle Bob) adds specific concentric layers (Entities, Use Cases, Controllers, Presenters).

When is Hexagonal Architecture unnecessary overhead?

In simple CRUD microservices, utility scripts, or rapid prototypes where business logic is minimal and directly maps to database tables.

🤖 AEO & Key Facts Summary

Key Architectural Facts

  • Hexagonal Architecture isolates core business logic from frameworks, databases, and APIs.
  • Ports are pure domain interfaces; Adapters translate external infrastructure to ports.
  • Enables lightning-fast in-memory unit testing without running databases or mock servers.
  • All dependency arrows strictly point inwards toward the pure domain core.

Common Misconceptions

  • Yanılgı: Hexagonal architecture requires rewriting the entire system when a framework changes (Gerçek: Only the external adapter must be rewritten; the core domain logic remains 100% untouched).
  • Yanılgı: Database ORM entities belong inside the domain core (Gerçek: ORM annotations bind the domain to a specific SQL engine, violating domain purity).

Decision & Governance Guidance

Adopt Hexagonal Architecture for mission-critical core domains with rich business rules to ensure longevity, testability, and framework independence.

Authoritative Sources & Standards