Hexagonal Architecture

Featured image

In the ever-changing world of software development, crafting applications that are both maintainable and adaptable is a constant challenge. Hexagonal architecture, also known as ‘Ports and Adapters’, provides an elegant solution to this problem, emphasizing separation of concerns and testability.

Why use Hexagonal Architecture

The core idea behind hexagonal architecture is to isolate the business domain (the heart of the application) from the technical details of infrastructure, databases, user interfaces, and external services. This isolation is where the magic lies, as there is no business logic in the adapters they are easily replaceable, this means that replacing the UI, Database, or any other adapter is no longer a daunting task.

  • Loose Coupling : Hexagonal architecture decouples core business logic from infrastructure concerns. This means that the how of databases, UIs, or external systems doesn’t dictate the structure of the domain logic.
  • Improved Testability : With a well-isolated core, focusing on writing unit tests for business logic without the overhead of setting up databases or mocking web services becomes easier.
  • Flexibility : Need to switch from a relational database to a NoSQL solution? Want to change your UI framework? Hexagonal architecture makes these transitions smoother by allowing you to replace adapters without disrupting the core.
  • Domain-Driven Design (DDD) Alignment : This pattern naturally complements DDD by placing emphasis on isolating and modeling your core business domain. For more information on Domain Driven Design please read my article
  • Maintainability : Thanks to the separation of concerns the code should become easier to maintain.

Principals of Hexagonal Architecture

The term “hexagonal” is more metaphorical than literal. Visualize your application core as the center of a hexagon. Each side of the hexagon represents a potential port where an adapter can connect.

  • The Core : This is the heart of your application, containing the pure, unadulterated business logic and domain models. It defines the essential behavior of your system, oblivious to the outside world.
  • Ports : These are interfaces defined within your core domain. They represent the operations that the core needs to perform or the data it requires. Ports are the points where the outside world can interact with your core.
  • Adapters : Adapters are the concrete implementations that connect the core logic to external dependencies. They might adapt database interactions, user interface elements, file system access, web services, or any other technical implementation required by your application.
    • Primary Adapters : Initiate actions upon your core (i.e a REST API, or a messaging Consumer)
    • Secondary Adapters : Allow the core to work with external services (i.e. Send e-mails, Events onto a bus, Store entities in a Database, ect.)

Simple Example

Lets say you have a bounded Context with an Application Core of Products.

  • Port : ProductList (An interface that has a method such as GetAvailableProductsForUser(User) )
  • Primary Adapter : ProductsController (A REST Controller that receives a request for products from an authenticated users and returns the list of available products)
  • Secondary Adapter : MsSqlProductRepository (Fetches required products data from MsSql for the Core)

Considerations

  • Use Interfaces : Ensure your core depends on your Ports (Interfaces), not Concrete Implementations.
  • Inversion of Control : Dependency Injects can really make your life here but wiring up your Adapters.

Conclusion

Hexagonal Architecture, though it may introduce a bit of initial overhead, offers significant long-term benefits in terms of adaptability, maintainability, and testability. If you’re building applications where these qualities are crucial, this pattern is a compelling choice.