Overview

Hexagonal Architecture, also known as Ports and Adapters pattern, was introduced by Alistair Cockburn. It aims to create loosely coupled application components that can be easily connected to their software environment through ports and adapters. This makes the application equally testable in isolation, with real databases, or with mock databases.

Core Concepts

Application Core

The business logic and domain model, independent of external concerns

  • Domain entities
  • Business rules
  • Use cases
  • Domain services

Ports

Interfaces that define how the application core communicates with the outside world

  • Input ports (driving)
  • Output ports (driven)
  • Repository interfaces
  • Service interfaces

Adapters

Concrete implementations that connect ports to external systems

  • Web controllers
  • Database repositories
  • Message handlers
  • External service clients

External Systems

Outside world components that interact with the application

  • Databases
  • Web services
  • Message queues
  • File systems

Key Principles

Dependency Inversion

The application core depends on abstractions (ports), not concrete implementations

Isolation of Business Logic

Business rules are separated from infrastructure concerns

Testability

Easy to test business logic in isolation using mock adapters

Technology Agnostic

Core business logic is independent of specific technologies

Adapter Types

Primary Adapters (Driving)

Initiate interactions with the application core

  • REST API controllers
  • GraphQL resolvers
  • CLI interfaces
  • Event handlers
  • Scheduled jobs

Secondary Adapters (Driven)

Provide services to the application core

  • Database repositories
  • External API clients
  • Email services
  • File storage
  • Message publishers

Benefits

Testability

Easy unit testing with mock adapters

Maintainability

Clear separation of concerns

Flexibility

Easy to swap implementations

Technology Independence

Business logic not tied to frameworks

Parallel Development

Teams can work on different adapters independently

Legacy Integration

Easy to integrate with existing systems

Implementation Structure

Typical Project Structure

src/
├── domain/
│   ├── entities/
│   ├── services/
│   └── ports/
│       ├── input/
│       └── output/
├── application/
│   └── usecases/
├── adapters/
│   ├── input/
│   │   ├── web/
│   │   ├── cli/
│   │   └── messaging/
│   └── output/
│       ├── persistence/
│       ├── external/
│       └── messaging/
└── configuration/

AWS Implementation

Primary Adapters

  • API Gateway - REST/GraphQL endpoints
  • Lambda - Serverless handlers
  • SQS/SNS - Message-driven adapters
  • EventBridge - Event-driven adapters

Secondary Adapters

  • DynamoDB - NoSQL persistence
  • RDS - Relational persistence
  • S3 - File storage adapter
  • SES - Email service adapter

Application Core

  • Lambda Layers - Shared business logic
  • ECS/EKS - Containerized applications
  • Step Functions - Complex workflows

Challenges & Considerations

Initial Complexity

More upfront design and structure required

Over-engineering

May be overkill for simple applications

Learning Curve

Team needs to understand the pattern

Performance Overhead

Additional abstraction layers may impact performance

Ideal Use Cases

Complex Business Logic

Applications with rich domain models and business rules

Multiple Interfaces

Systems that need web, mobile, and API interfaces

Legacy Integration

Modernizing systems while maintaining existing integrations

High Test Coverage

Applications requiring extensive automated testing

Comparison with Other Patterns

Aspect Hexagonal Layered Clean Architecture
Testability Excellent Good Excellent
Flexibility High Medium High
Complexity Medium Low High
Learning Curve Medium Low High

Infrastructure as Code Samples

AWS Whitepapers & Documentation