Ports and Adapters (Hexagonal) architecture — isolate business logic from external concerns via explicit boundaries.
TRIGGER when: user asks about ports and adapters, hexagonal architecture, hexagon architecture, Alistair Cockburn, clean architecture, onion architecture, layered architecture comparison, adapters (driving/primary adapter, driven/secondary adapter, adapter pattern boundary), ports (inbound port, outbound port, application port), layers (domain layer, application core, infrastructure layer, use case), isolation (dependency inversion in practice, testable business logic, decouple framework, boundary protection). DO NOT USE when: user asks about general OOP/SOLID principles in the abstract — use `oop-principles` instead. Note: DIP from `oop-principles/solid` is the theoretical foundation of this pattern.
Installation
Installer avec Codex ou Claude Copiez ce prompt, collez-le dans Codex, Claude ou un autre assistant, puis laissez-le vérifier la page du skill et l'installer pour vous.
Ports and Adapters (Hexagonal) architecture — isolate business logic from external concerns via explicit boundaries.
TRIGGER when: user asks about ports and adapters, hexagonal architecture, hexagon architecture, Alistair Cockburn, clean architecture, onion architecture, layered architecture comparison, adapters (driving/primary adapter, driven/secondary adapter, adapter pattern boundary), ports (inbound port, outbound port, application port), layers (domain layer, application core, infrastructure layer, use case), isolation (dependency inversion in practice, testable business logic, decouple framework, boundary protection). DO NOT USE when: user asks about general OOP/SOLID principles in the abstract — use `oop-principles` instead. Note: DIP from `oop-principles/solid` is the theoretical foundation of this pattern.
Ports and Adapters Architecture
Also called "Hexagonal Architecture" by Alistair Cockburn.
Core Idea
Isolate your business logic in the center ("hexagon"). Everything outside—databases, web frameworks, message queues, UI—connects through explicit ports and adapters. This inversion of dependencies makes business logic reusable and testable.
Structure
hexagon/
├── domain/ ← Business logic (center), no dependencies on outside
├── ports/
│ ├── driving/ ← Interfaces for external actors to call in
│ │ └── UserService.ts
│ └── driven/ ← Interfaces for the domain to call out
│ └── UserRepository.ts
├── use-cases/ ← Application layer, orchestrates domain
│ └── CreateUserUseCase.ts
adapters/
├── driving/ ← How external actors call the domain
│ ├── http/ ← REST controller
│ └── cli/ ← Command-line interface
└── driven/ ← How the domain calls external systems
├── postgres/ ← Concrete database implementation
├── email/ ← Email service implementation
└── cache/ ← Cache service implementation
Key Concepts
Term
Meaning
Port
Interface defined by the hexagon (domain). External systems implement it.
Adapter
Concrete implementation of a port. Translates between domain logic and external tools.
Driving / Primary
Ports where external actors (HTTP client, CLI user, scheduler) call into the domain.
Driven / Secondary
Ports where the domain calls out to external systems (database, cache, email).
Naming convention: For driving ports, use for_<action> (e.g., for_creating_users).
Advantages
Business logic is framework-agnostic — swap HTTP for gRPC without touching the domain
Testability: inject fakes for driven ports; test domain in isolation
Clarity: dependencies flow inward only; domain never depends on adapters
Scalability: add new adapters (new databases, new APIs) without changing the core
Application Workflow
When the user wants to apply or review Ports & Adapters:
Identify the boundary — where does business logic end and infrastructure begin? The hexagon edge is the answer.
Define the ports — write interfaces (not implementations) for every outbound dependency. Name them for_<action>.
Move logic inward — ensure domain code imports only other domain code, never framework/DB packages.
Write adapters — one concrete class per external system, implementing the matching port interface.
Read On Demand
Read When
File
Before/after TypeScript example showing the refactoring