π‘οΈ Hexagonal Architecture (Ports and Adapters)¶
Info
At ConnectSoft, Hexagonal Architecture (also known as the Ports and Adapters pattern) is a core design foundation used to ensure that systems are technology-agnostic, testable, and adaptable to change.
It reinforces the principles of domain purity, dependency inversion, and separation of concerns β enabling resilient, modular, cloud-native, and event-driven platforms.
π― Introduction¶
Hexagonal Architecture structures a system around a core domain logic, completely decoupled from external technologies such as databases, web frameworks, messaging systems, or UIs.
- The core defines the business rules and application logic.
- Ports represent abstract points of interaction β they define how the system communicates with the outside world.
- Adapters implement these ports to connect the system to external systems, protocols, or devices.
This ensures that technologies can change without impacting the domain, and testing can be performed purely at the domain level without reliance on infrastructure.
π§ Core Concepts¶
| Concept | Description |
|---|---|
| Domain Core | Business logic, use cases, and entities that express the real problem space. |
| Ports | Interfaces that define allowed interactions β inbound and outbound. |
| Adapters | Concrete implementations of ports to handle real-world technologies. |
ποΈ Structure Overview¶
flowchart TD
ExternalSystem1((User Interface))
ExternalSystem2((External API))
ExternalSystem3((Database))
ExternalSystem4((Message Broker))
ExternalSystem1 -->|Primary Adapter| PrimaryPort
ExternalSystem2 -->|Primary Adapter| PrimaryPort
SecondaryPort -->|Secondary Adapter| ExternalSystem3
SecondaryPort -->|Secondary Adapter| ExternalSystem4
PrimaryPort --> CoreDomain
CoreDomain --> SecondaryPort
β
Primary Adapters: Handle inbound communication (e.g., HTTP Controllers, CLI Interfaces).
β
Secondary Adapters: Handle outbound communication (e.g., Persistence, Event Publishing).
π Principles¶
-
Dependency Inversion:
The core defines the contracts (ports); infrastructure depends on the core, not vice versa. -
Isolation of Technology:
Frameworks, databases, and external services are kept at the boundary, easily swappable. -
Testability by Design:
Core domain can be tested independently using mock adapters. -
Adaptability and Resilience:
Changing a database, messaging broker, or API endpoint requires changes only in adapters.
π How It Connects to ConnectSoftβs Platform¶
Hexagonal Architecture underpins many ConnectSoft components:
- Microservices β with clean separation between business logic and API/DB layers.
- API Gateways β where request routing logic is completely decoupled from infrastructure.
- Event-Driven Services β emitting domain events through secondary ports without knowing delivery technology.
- AI Agents β interfacing domain logic with AI orchestration layers via adapter strategies.
π Hexagonal Architecture is the bridge between ConnectSoftβs domain-driven designs and its scalable, resilient, and cloud-native execution models.
π Summary of Core Concepts¶
| Area | ConnectSoft Approach |
|---|---|
| Domain Core | Owns use cases, entities, domain rules |
| Primary Ports | Define incoming actions (e.g., commands, queries) |
| Secondary Ports | Define outgoing actions (e.g., repository, events, APIs) |
| Primary Adapters | Implement inbound ports (e.g., REST controllers, gRPC) |
| Secondary Adapters | Implement outbound ports (e.g., repositories, brokers) |
| Isolation Strategy | Domain core is free from any external technology influence |
π§± Components of Hexagonal Architecture¶
In Hexagonal Architecture, systems are organized around roles, not technologies.
At ConnectSoft, each component of the hexagon is designed with strict responsibility boundaries to maximize resilience, testability, and maintainability.
π§ Domain Core (Inside the Hexagon)¶
The Domain Core encapsulates:
-
Entities
Represent domain objects with identity and lifecycle. -
Value Objects
Model descriptive aspects without identity. -
Aggregates
Group domain entities for consistency boundaries. -
Domain Services
Contain stateless operations that don't belong to a single entity. -
Use Cases (Application Services)
Orchestrate business workflows by invoking domain logic.
The core is completely pure β no frameworks, no infrastructure code, no external dependencies.
public interface IPlaceOrderUseCase
{
Task PlaceOrderAsync(Guid customerId, List<Guid> productIds);
}
β Ports (interfaces) are defined inside the core.
π Ports¶
Ports are abstract interfaces that define how the application communicates with the outside world.
| Port Type | Purpose | Example |
|---|---|---|
| Primary Ports | Allow external systems to invoke core functionality | IPlaceOrderUseCase (e.g., API calls) |
| Secondary Ports | Allow core to communicate outward to external services | IOrderRepository (e.g., database access) |
Primary Ports¶
Interfaces exposed by the Core, to be called by external actors.
Adapters like API Controllers or CLI commands implement the wiring to call these ports.
Secondary Ports¶
Interfaces that the Core uses to perform external operations.
public interface ICustomerRepository
{
Task<Customer> GetByIdAsync(Guid id);
Task SaveAsync(Customer customer);
}
Adapters like database repositories, message publishers, or HTTP clients implement these interfaces.
π― Primary Adapters (Inbound)¶
Primary Adapters implement external inputs, adapting them into port invocations.
| Adapter Type | Example |
|---|---|
| REST API Controller | Exposes HTTP endpoints that call use cases |
| gRPC Service | Handles remote calls to the system |
| CLI Command | Accepts console input |
| Messaging Consumer | Receives event messages |
Example: REST API Controller Adapter
[ApiController]
[Route("api/orders")]
public class OrderController : ControllerBase
{
private readonly IPlaceOrderUseCase _placeOrder;
public OrderController(IPlaceOrderUseCase placeOrder)
{
_placeOrder = placeOrder;
}
[HttpPost]
public async Task<IActionResult> PlaceOrder([FromBody] PlaceOrderRequest request)
{
await _placeOrder.PlaceOrderAsync(request.CustomerId, request.ProductIds);
return Ok();
}
}
β The controller doesn't contain business logic β it delegates to the Core.
π― Secondary Adapters (Outbound)¶
Secondary Adapters implement external outputs, fulfilling secondary ports.
| Adapter Type | Example |
|---|---|
| Database Repository | Persists aggregates to a database |
| Message Publisher | Publishes events to a broker |
| External API Client | Calls third-party services |
| File Storage Client | Saves files to blob storage |
Example: Repository Adapter
public class CustomerRepository : ICustomerRepository
{
private readonly ApplicationDbContext _dbContext;
public CustomerRepository(ApplicationDbContext dbContext)
{
_dbContext = dbContext;
}
public async Task<Customer> GetByIdAsync(Guid id)
{
return await _dbContext.Customers.FindAsync(id);
}
public async Task SaveAsync(Customer customer)
{
_dbContext.Customers.Update(customer);
await _dbContext.SaveChangesAsync();
}
}
β Infrastructure details (e.g., EF Core) are hidden from the domain.
π§© Full Component Diagram¶
flowchart TB
PrimaryAdapter1((REST Controller))
PrimaryAdapter2((CLI Command))
PrimaryAdapter3((gRPC Service))
SecondaryAdapter1((Database Repository))
SecondaryAdapter2((Message Broker Publisher))
PrimaryAdapter1 -->|Invokes| PrimaryPort
PrimaryAdapter2 -->|Invokes| PrimaryPort
PrimaryAdapter3 -->|Invokes| PrimaryPort
PrimaryPort --> CoreDomain
CoreDomain --> SecondaryPort
SecondaryPort --> SecondaryAdapter1
SecondaryPort --> SecondaryAdapter2
β
Ports define the interaction contracts.
β
Adapters connect real-world concerns to the pure core logic.
π Component Responsibilities Summary¶
| Component | Responsibility |
|---|---|
| Domain Core | Business rules and use cases, technology-agnostic |
| Primary Ports | Expose system capabilities (application services) |
| Secondary Ports | Request external capabilities (e.g., persistence) |
| Primary Adapters | Translate external requests into core use case invocations |
| Secondary Adapters | Implement core output contracts for infrastructure interaction |
π§± Layered Structure and Flow in Hexagonal Architecture¶
At ConnectSoft, every Hexagonal service is built around strict, traceable dependency rules and layered communication flow to maintain system integrity, adaptability, and clean testability.
π§© Logical Layering¶
| Layer | Description | ConnectSoft Focus |
|---|---|---|
| Domain Core | Pure business logic and use cases, no dependencies outward | β |
| Ports | Contracts to communicate in and out of the core | β |
| Adapters | Technology-specific implementations of ports | β |
| Infrastructure | External systems like databases, APIs, queues | β |
π Dependency Rules¶
β Adapters and infrastructure depend on Core, never the other way around.
β Ports are owned by the Core and implemented by Adapters.
β Infrastructure can change without modifying the Domain Core.
flowchart TB
UIClient --> PrimaryAdapter
PrimaryAdapter --> PrimaryPort
PrimaryPort --> DomainCore
DomainCore --> SecondaryPort
SecondaryPort --> SecondaryAdapter
SecondaryAdapter --> ExternalService
β One-way arrows always point toward the Core.
π₯ Flow of Execution¶
- External request hits a Primary Adapter (e.g., API call).
- Primary Adapter calls a Primary Port (use case interface).
- Core Domain processes business rules.
- Core calls Secondary Ports (repository, publisher, client).
- Secondary Adapters interact with Infrastructure (DB, message broker).
π§ C# Code Example: Full Flow¶
1. Primary Port (Use Case Interface)¶
public interface ICreateOrderUseCase
{
Task<Guid> CreateOrderAsync(Guid customerId, List<Guid> productIds);
}
2. Domain Core Implementation (Use Case)¶
public class CreateOrderService : ICreateOrderUseCase
{
private readonly IOrderRepository _orderRepository;
public CreateOrderService(IOrderRepository orderRepository)
{
_orderRepository = orderRepository;
}
public async Task<Guid> CreateOrderAsync(Guid customerId, List<Guid> productIds)
{
var order = Order.Create(customerId, productIds);
await _orderRepository.SaveAsync(order);
return order.Id;
}
}
β The domain core only depends on Ports (interfaces).
3. Secondary Port (Repository Interface)¶
4. Secondary Adapter (Infrastructure)¶
public class OrderRepository : IOrderRepository
{
private readonly AppDbContext _dbContext;
public OrderRepository(AppDbContext dbContext)
{
_dbContext = dbContext;
}
public async Task SaveAsync(Order order)
{
_dbContext.Orders.Add(order);
await _dbContext.SaveChangesAsync();
}
}
β The repository depends on EF Core but the core does not.
5. Primary Adapter (REST Controller)¶
[ApiController]
[Route("api/orders")]
public class OrdersController : ControllerBase
{
private readonly ICreateOrderUseCase _createOrder;
public OrdersController(ICreateOrderUseCase createOrder)
{
_createOrder = createOrder;
}
[HttpPost]
public async Task<IActionResult> CreateOrder([FromBody] CreateOrderRequest request)
{
var orderId = await _createOrder.CreateOrderAsync(request.CustomerId, request.ProductIds);
return Ok(new { OrderId = orderId });
}
}
β Controller knows nothing about the database, message queues, or infrastructure.
π Layered Mapping Summary¶
| Layer | Example in ConnectSoft |
|---|---|
| Domain Core | Order, OrderService |
| Primary Port | ICreateOrderUseCase |
| Secondary Port | IOrderRepository |
| Primary Adapter | OrdersController |
| Secondary Adapter | OrderRepository |
π Best Practices for Layering at ConnectSoft¶
β
Protect the Core at all costs β never let infrastructure leak in.
β
Define clear Ports for inbound and outbound operations.
β
Favor Dependency Injection for all Adapter bindings.
β
Keep Adapters dumb β they only translate requests/responses.
Tip
If an infrastructure change (like switching from SQL to NoSQL) requires changes inside your domain layer,
it signals a violation of Hexagonal principles.
π Benefits and Trade-Offs of Hexagonal Architecture¶
At ConnectSoft, adopting Hexagonal Architecture is not just a preference β it is a strategic choice that aligns every system with domain purity, adaptability, and enterprise resilience.
However, like any powerful architecture, it introduces both significant benefits and some complexities that must be managed wisely.
β Key Benefits¶
| Benefit | Description |
|---|---|
| Technology Agnosticism | Core logic is isolated from frameworks, databases, and protocols. |
| Testability by Default | Core can be tested independently of infrastructure, with mock ports. |
| Flexibility and Adaptability | Swapping infrastructure (e.g., database, broker) does not impact core business rules. |
| Clear Responsibility Separation | Adapters focus on translation; Core focuses on business. |
| Portability | Core logic can be reused across different delivery mechanisms (e.g., API, CLI, Message Bus). |
| Resilience to Change | Evolving external technologies is simplified β only adapters change. |
π Diagram: Benefits Mapping¶
flowchart LR
HexagonalArchitecture --> TechnologyAgnostic
HexagonalArchitecture --> Testable
HexagonalArchitecture --> Flexible
HexagonalArchitecture --> ClearSeparation
HexagonalArchitecture --> Portable
HexagonalArchitecture --> Resilient
β Each benefit strengthens ConnectSoftβs platform evolution strategy.
β οΈ Trade-Offs and Challenges¶
| Challenge | Description |
|---|---|
| Initial Complexity | Setting up layers (ports, adapters, dependency injection) requires careful upfront work. |
| Overengineering Risk | For small projects, Hexagonal layering can feel heavy or unnecessary. |
| Developer Onboarding Time | New developers need to learn the internal architecture to navigate effectively. |
| Multiple Layers of Indirection | Following requests through ports and adapters adds cognitive load. |
π₯ Example of Complexity¶
Without discipline, developers might:
- Duplicate adapter logic across services.
- Leak database entities into the Domain Core.
- Violate dependency inversion unintentionally.
Warning
In ConnectSoft platforms, strict architectural linting is enforced to prevent these mistakes.
No direct infrastructure access is permitted from domain layers.
π§ Best Practices to Maximize Benefits at ConnectSoft¶
β
Template First
Use ConnectSoft base templates that scaffold ports, adapters, dependency wiring, and testing stubs.
β
Strict Core Protection
Ensure that all dependencies point inward toward the domain. No accidental outward calls.
β
Explicit Ports Always
Do not rely on generic services or dynamic bindings. Ports should be clear, versioned, and traceable.
β
Test Core in Isolation
Build unit tests directly against use cases without real database, queues, or HTTP servers.
β
Evolve Adapters, Not Core
Adapters can be reworked freely (e.g., from REST to GraphQL) without touching the domain.
β
Invest in Onboarding
Document and visualize the Hexagonal structure for every new team member.
π Benefit vs Trade-Off Summary Table¶
| Category | Benefit | Trade-Off |
|---|---|---|
| Agility | Infrastructure independence | Requires rigorous layering |
| Quality | Easy unit testing | Initial learning curve |
| Flexibility | Easy to adapt to technology shifts | More moving parts to manage |
| Clarity | Clear separation of concerns | Slight overhead for small apps |
Tip
At ConnectSoft, we apply Hexagonal Architecture even for internal tools and microservices β
because small systems today can become mission-critical tomorrow.
π§© ConnectSoft Hexagonal Architecture Blueprint¶
At ConnectSoft, Hexagonal Architecture is not just a theoretical model β
it is the operational blueprint for how we build SaaS platforms, microservices ecosystems, API gateways, and AI orchestration engines.
Every system we design aligns with the Hexagonal pattern to ensure:
- β Business-first domain modeling
- β Technology-agnostic resilience
- β Infrastructure adaptability
- β Cloud-native and event-driven enablement
ποΈ Platform-Wide Application of Hexagonal Principles¶
| Platform Area | Hexagonal Application Pattern |
|---|---|
| Microservices | Each service encapsulates domain logic, ports, and adapters. |
| API Gateway | Gateway routes requests to primary ports of downstream services. |
| Event-Driven Architecture | Consumers and producers adapt to ports for event handling. |
| AI Engines (Semantic Kernel) | Core AI logic exposed through ports, adapters integrate storage, APIs. |
| SaaS Tenant Management | Tenant lifecycle logic isolated via ports; adapters manage DB, auth, billing. |
π ConnectSoft Example: SaaS Service Hexagon¶
flowchart TD
WebClient -->|HTTP POST| CreateTenantAdapter
CLI -->|CLI Command| CreateTenantAdapter
EventConsumer -->|Event| CreateTenantAdapter
CreateTenantAdapter --> CreateTenantPort
CreateTenantPort --> TenantServiceDomainCore
TenantService --> TenantRepositoryPort
TenantService --> BillingServicePort
TenantRepositoryPort --> TenantRepositoryAdapter
BillingServicePort --> BillingApiAdapter
β
External actors (Web, CLI, Event Consumer) interact via Primary Adapters.
β
Domain Core enforces business rules through Ports.
β
Secondary Adapters implement infrastructure-specific operations.
π οΈ Sample Hexagonal Use Case: Tenant Registration¶
Primary Port¶
public interface IRegisterTenantUseCase
{
Task<Guid> RegisterAsync(string companyName, string adminEmail);
}
Domain Service (Use Case Implementation)¶
public class RegisterTenantService : IRegisterTenantUseCase
{
private readonly ITenantRepository _tenantRepository;
private readonly IBillingService _billingService;
public RegisterTenantService(ITenantRepository tenantRepository, IBillingService billingService)
{
_tenantRepository = tenantRepository;
_billingService = billingService;
}
public async Task<Guid> RegisterAsync(string companyName, string adminEmail)
{
var tenant = Tenant.Create(companyName, adminEmail);
await _tenantRepository.SaveAsync(tenant);
await _billingService.CreateAccountAsync(tenant.Id);
return tenant.Id;
}
}
Secondary Ports¶
public interface ITenantRepository
{
Task SaveAsync(Tenant tenant);
}
public interface IBillingService
{
Task CreateAccountAsync(Guid tenantId);
}
Secondary Adapters¶
public class TenantRepository : ITenantRepository
{
// Save to database
}
public class BillingApiClient : IBillingService
{
// Call external billing API
}
β Core logic never touches database or APIs directly.
π Blueprint: Across ConnectSoft Ecosystem¶
| Service Type | Ports Exposed | Adapters Implemented |
|---|---|---|
| Order Service | IPlaceOrderUseCase, IOrderRepository |
REST Controller, SQL Repo, Kafka Producer |
| User Management | IRegisterUserUseCase, IUserRepository |
REST API Adapter, Azure AD B2C Adapter |
| Billing Service | IChargeTenantUseCase, IPaymentGatewayPort |
gRPC Adapter, Stripe API Adapter |
| AI Orchestration Agent | IAnalyzeInputUseCase, IKnowledgeBasePort |
HTTP Adapter, Blob Storage Adapter |
| API Gateway | Routes to service primary ports only | Path-to-port routing Adapter |
π Hexagonal Across Event-Driven Workflows¶
- Events emitted from the Core through Secondary Ports.
- Event Consumers wired as Primary Adapters that trigger use cases.
- Ports define contracts for publishing and consuming domain events.
sequenceDiagram
API->>PrimaryAdapter: HTTP Request
PrimaryAdapter->>UseCase: Execute Command
UseCase->>DomainEntity: Apply Changes
UseCase->>SecondaryPort: Publish Event
SecondaryAdapter->>MessageBroker: Publish Domain Event
β All event handling is port-driven, not infrastructure-driven.
π ConnectSoft Hexagonal Blueprint Principles¶
| Principle | ConnectSoft Practice |
|---|---|
| Isolate Domain Logic | Never depend on frameworks, databases, or brokers inside core |
| Explicit Ports | Clear, well-defined interfaces for all interactions |
| Adaptable Adapters | Infrastructure swaps do not impact core functionality |
| Event and Command Driven | Ports serve both request/response and event-based workflows |
| Template-First Execution | All new services scaffolded with hexagonal templates |
Tip
Hexagonal Architecture at ConnectSoft is not an optional style β
it is the platform enforcement mechanism that guarantees agility, resilience, and scale for every product we deliver.
π¦ Real-World Use Cases of Hexagonal Architecture at ConnectSoft¶
Hexagonal Architecture enables ConnectSoft systems to be resilient, modular, and cloud-native, across a wide variety of real-world domains and technical demands.
Below are selected examples showcasing practical applications of ports and adapters in different environments.
ποΈ E-Commerce Microservice: Order Management¶
π Scenario¶
- Customers place orders via a web app.
- Orders must be persisted, inventory adjusted, and events published for further processing.
π§ Structure¶
| Layer | Implementation |
|---|---|
| Primary Adapters | REST API Controller (HTTP) |
| Core Ports | IPlaceOrderUseCase, IOrderRepository, IEventPublisher |
| Secondary Adapters | SQL Database Adapter (EF Core), Kafka Publisher Adapter |
π οΈ Flow Diagram¶
flowchart TD
WebClient -->|HTTP POST| OrderApiController
OrderApiController --> PlaceOrderUseCase
PlaceOrderUseCase --> OrderRepository
PlaceOrderUseCase --> EventPublisher
OrderRepository --> Database
EventPublisher --> Kafka
β All infrastructure is accessed through Ports only.
π§© Key Best Practices¶
- Core domain owns
Orderaggregate lifecycle. - Order placement emits
OrderPlacedEventto Kafka viaIEventPublisher. - Event publishing and database saving are fully decoupled.
π€ AI Workflow Orchestration Service¶
π Scenario¶
- AI agents execute workflows and store intermediate results.
- Responses must be written to both blob storage and exposed via API.
π§ Structure¶
| Layer | Implementation |
|---|---|
| Primary Adapters | Semantic Kernel Adapter, REST Controller |
| Core Ports | IExecuteWorkflowUseCase, IStoragePort |
| Secondary Adapters | Azure Blob Storage Adapter, Database Adapter |
π οΈ Flow Diagram¶
flowchart TD
SemanticKernelAgent --> SemanticAdapter
SemanticAdapter --> ExecuteWorkflowUseCase
ExecuteWorkflowUseCase --> StoragePort
StoragePort --> AzureBlobStorageAdapter
StoragePort --> DatabaseAdapter
β AI engine code only interacts with the core, not with Azure SDKs or APIs directly.
π§© Key Best Practices¶
- Workflow execution logic remains storage-agnostic.
- Adapters switchable between Azure, AWS, or even local storage without touching core.
π‘ Event-Driven Inventory Service¶
π Scenario¶
- Inventory Service reacts to
OrderPlacedEventto reserve stock. - Service must handle failures gracefully without affecting ordering flow.
π§ Structure¶
| Layer | Implementation |
|---|---|
| Primary Adapters | Kafka Consumer Adapter |
| Core Ports | IReserveStockUseCase, IInventoryRepository |
| Secondary Adapters | SQL Repository, Event Publisher Adapter |
π οΈ Flow Diagram¶
flowchart TD
KafkaBroker --> KafkaConsumer
KafkaConsumer --> ReserveStockUseCase
ReserveStockUseCase --> InventoryRepository
InventoryRepository --> SQLDatabase
β Event consumption acts through a primary adapter into a pure core.
π§© Key Best Practices¶
- Inventory adjustments based only on domain events.
- Service idempotency and retry strategies managed at adapter layer.
- Side-effects (e.g., publishing confirmation events) are separated via secondary ports.
π Recap: Best Practices for Hexagonal Use Cases¶
| Practice | Description |
|---|---|
| Always Separate Adapters | Keep all technologies outside the domain core. |
| Model Ports Explicitly | Interfaces for both inbound (commands) and outbound (actions). |
| Isolate Event Handling | Events enter via Primary Adapters, not tangled into core logic. |
| Favor Port-Based Testing | Core is tested by mocking ports, not infrastructure. |
| Infrastructure Changes are Adapter Changes | Core remains stable across technology shifts. |
Tip
At ConnectSoft, every real-world service β from microservices to AI agents β
is built ports-first, domain-centered, and adapter-isolated to guarantee longevity, maintainability, and speed of innovation.
π§ Hexagonal Architecture vs Other Architectural Styles¶
At ConnectSoft, we recognize that Hexagonal Architecture did not emerge in isolation β
it evolved alongside other architectures that aim to improve modularity, testability, and adaptability.
Understanding how Hexagonal compares ensures clarity and consistent application across all platforms.
π High-Level Comparison Table¶
| Architecture | Focus | How Hexagonal Relates or Improves |
|---|---|---|
| Layered Architecture | Strict vertical layers (UI β Business β Data) | Hexagonal removes layer-to-layer rigidity via Ports/Adapters. |
| Onion Architecture | Domain Core in center, dependencies inward | Hexagonal formalizes inbound/outbound communication via Ports. |
| Clean Architecture | Policy-driven design, frameworks at outer circle | Hexagonal is Clean in spirit, but interaction-focused. |
| Domain-Driven Design (DDD) | Modeling domain with Entities, Aggregates, etc. | Hexagonal hosts DDD tactical patterns inside cleanly. |
| Microservices Architecture | Independently deployable services with bounded contexts | Hexagonal is inside each microservice to enforce internal consistency. |
ποΈ Layered Architecture vs Hexagonal¶
Traditional Layered Architecture:
flowchart TB
UI --> BusinessLogic
BusinessLogic --> DataAccess
- Each layer calls the next downward.
- Hard to swap infrastructure without touching business logic.
- Risk of leaking DB entities into UI layer.
Hexagonal Architecture:
flowchart TB
PrimaryAdapter1 --> PrimaryPort --> CoreDomain
CoreDomain --> SecondaryPort --> SecondaryAdapter1
- No direct layer-to-layer coupling.
- Core communicates through Ports only.
- Infrastructure is completely isolated.
Warning
Layered architectures often cause infrastructure bleeding into business logic.
Hexagonal locks the business inside protective ports.
π§ Onion Architecture vs Hexagonal¶
Onion Architecture:
flowchart TB
UI --> ApplicationService --> DomainModel --> Infrastructure
- Clear inward dependencies.
- Strong domain core protection.
Hexagonal Architecture:
- Same inward dependency rules.
- Adds Ports explicitly:
- Define how external world interacts with the Core (not just what depends).
β Hexagonal = Onion + Ports/Adapters + Stronger boundary contracts.
π§Ή Clean Architecture vs Hexagonal¶
Clean Architecture (by Uncle Bob):
- Entities and Use Cases at the center.
- Interface Adapters around them.
- Frameworks (DB, Web, etc.) at the outermost circle.
Hexagonal Architecture:
- Same inside-out dependency rule.
- Focuses more on dynamic interaction points (Ports/Adapters) than just static layers.
| Aspect | Clean Architecture | Hexagonal Architecture |
|---|---|---|
| Layering Focus | Static code organization | Interaction flow (ports) |
| Domain Protection | β | β |
| External Isolation | β | β |
| Emphasis | Policy/Layered Circles | Interaction Points/Boundaries |
β Hexagonal emphasizes real-world behavior orchestration, making integration points first-class citizens.
π§± Domain-Driven Design (DDD) and Hexagonal¶
DDD Tactical Patterns:
- Entities
- Value Objects
- Aggregates
- Repositories
- Domain Events
- Application Services
Where Hexagonal Architecture fits:
| DDD Tactical Artifact | Hexagonal Placement |
|---|---|
| Entity, Aggregate, Value Object | Inside Core Domain |
| Repository Interface | Secondary Port |
| Application Service (Use Case) | Primary Port |
| Domain Event Publisher | Secondary Port |
β Hexagonal is the architecture model that naturally hosts DDD tactical patterns inside bounded, protected cores.
Info
In ConnectSoft SaaS services, every microservice applies Hexagonal Architecture + DDD together.
π Microservices Architecture and Hexagonal¶
| Microservices Aspect | Hexagonal Alignment |
|---|---|
| Bounded Contexts | One Hexagon per microservice. |
| Independent Deployment | Primary/Secondary Adapters allow different delivery models per service. |
| Resilience and Evolution | Ports abstract infrastructure changes without touching Core. |
β
Microservices define service-level boundaries;
β
Hexagonal Architecture defines internal modular boundaries inside each service.
π Visual Summary: How Architectures Evolved¶
graph LR
LayeredArchitecture --> OnionArchitecture
OnionArchitecture --> CleanArchitecture
CleanArchitecture --> HexagonalArchitecture
β Hexagonal is the next evolution, focusing not only on code structure but on system communication flows.
π Quick Takeaways¶
| Topic | Quick Insight |
|---|---|
| Hexagonal vs Layered | Ports break rigid vertical coupling. |
| Hexagonal vs Onion | Adds dynamic Ports/Adapters to static inner/outer layers. |
| Hexagonal vs Clean | Similar dependency inversion, but Hexagonal elevates dynamic boundaries. |
| Hexagonal and DDD | Perfectly hosts Entities, Aggregates, Repositories, Use Cases inside. |
| Hexagonal in Microservices | Forms the inner architecture of every independently deployable service. |
π§© Conclusion¶
At ConnectSoft, Hexagonal Architecture is not a trend β it is a core operating model that ensures our systems are:
- π₯ Business-centered, not technology-driven
- π Resilient and isolated from infrastructure volatility
- π Adaptable to change without heavy refactoring
- π Highly testable and observable from day one
- π οΈ Cloud-native and microservice-ready at all levels
By enforcing Ports and Adapters boundaries,
we create systems that scale, evolve, and integrate seamlessly with new technologies, frameworks, and platforms β
without touching the domain logic that powers our business.
β
Whether building a SaaS product, an AI engine, a platform microservice, or a gateway,
β
Hexagonal Architecture enables ConnectSoft teams to focus on what matters most: the business capabilities we deliver.
π References¶
π Internal ConnectSoft Documentation¶
- Domain-Driven Design (DDD)
- Clean Architecture
- Event-Driven Architecture
- Microservices
- Cloud-Native Principles