Posts Tagged ‘HexagonalArchitecture’
[MiamiJUG] Decoupling Business Logic via Ports and Adapters Architecture
Lecturer
Dr. Alistair Cockburn is an internationally recognized expert in software methodology and a co-author of the Agile Manifesto. Named one of the “42 Greatest Software Professionals of All Time” in 2020, Alistair has spent decades refining project management and software architecture patterns. He is the creator of the “Hexagonal Architecture,” more formally known as the Ports and Adapters pattern, which he developed to address the chronic issue of technology “leakage” in enterprise software.
Abstract
This article examines the Ports and Adapters architecture (Hexagonal Architecture) as a solution for isolating business logic from external technical dependencies. By treating an application as a self-contained component surrounded by a “test moat,” developers can ensure that core logic remains technology-agnostic and highly maintainable. The analysis covers the methodology of separating driving and driven actors, the benefits of automated regression testing in isolation, and the structural implementation of this pattern in modern development environments.
The Rationale for Isolation
The primary motivation behind Ports and Adapters is the frustration caused by software that cannot easily swap databases, drivers, or user interfaces. Traditional architectures often allow I/O concerns—such as SQL queries or framework-specific logic—to bleed into the business core. When these external technologies become obsolete or unavailable, the business logic is held hostage by the technical debt.
Alistair characterizes the application as a “component in a component library” that should know nothing about the outside world. By isolating the logic, teams can protect their code from the instability of external dependencies, such as an unavailable database or a required technology upgrade.
Ports, Adapters, and the “Inside-Outside” Divide
The architecture is structured around two primary concepts that define the boundary of the application core:
- Ports: These are interfaces defined by the core that specify what the application needs to interact with the world.
- Adapters: These are implementation-specific wrappers that translate between the port’s interface and external technologies (e.g., a REST API or a PostgreSQL database).
This separation distinguishes between Driving Adapters (primary actors that initiate actions in the core, like a CLI or GUI) and Driven Adapters (secondary actors that the core uses, like a database or external service). This distinction creates a “test moat” that allows the application to be run in isolation using mock adapters, enabling 100% automated regression testing without live external systems.
Implementation Strategy and Sequence
Effective implementation of Ports and Adapters requires a disciplined folder structure that explicitly separates the “Inside” (Domain/Core) from the “Outside” (Adapters). This allows for a “development sequence” where the business logic is written and fully tested first, using in-memory mock adapters. Only after the core logic is verified are the actual production adapters—such as the database implementation or the web front-end—developed. This approach ensures that the most valuable part of the software remains flexible and resistant to technology leakage over time.
Links:
[VoxxedDaysTicino2026] Why Hexagonal and Onion Architectures Are Answers to the Wrong Question
Lecturer
Oliver Drotbohm is a senior principal software engineer at Broadcom, formerly part of the Spring engineering team at VMware for over 15 years. He has contributed significantly to Spring Data, focusing on repository abstractions, and more recently on architectural topics like Spring Modulith. Oliver is an advocate for modular software design and has spoken extensively on domain-driven design and system architecture. Relevant links include his GitHub profile (https://github.com/odrotbohm) and X account (https://x.com/odrotbohm).
Abstract
This article delves into Oliver Drotbohm’s critique of popular separation-of-concerns architectures like hexagonal and onion models, arguing they often prioritize decoupling over cohesion, leading to suboptimal code structures. Through theoretical analysis and practical examples, it explores software design principles rooted in coupling, cohesion, and anticipated changes. The discussion highlights trade-offs, the role of tools like Spring Modulith, and advocates for functional decomposition to achieve maintainable systems.
Fundamental Principles of Software Design and Cost
Software development’s primary cost lies in modifications rather than initial creation, as most efforts involve evolving existing systems. Oliver draws from Kent Beck’s interpretation of Edward Yourdon and Larry Constantine’s work, positing that change costs are tied to coupling between code elements—classes, packages, or modules. Coupling manifests when alterations in one area necessitate changes elsewhere, with its nature depending on the change type (e.g., database migration versus UI enhancement).
To minimize costs, decoupling is essential, but it introduces its own overhead, such as additional interfaces and implementations. Oliver emphasizes cohesion as the counterbalance: intentional coupling in appropriate places to collocate elements for common changes. Effective design creates cohesive units loosely coupled to others, essentially betting on future change patterns.
Systems emerge not just from parts but their interactions, per Russell Ackoff’s philosophy. Thus, design involves defining cohesive elements, promoting entry points, and establishing connections. This foundational view critiques architectures that overlook these dynamics.
Critique of Separation-of-Concerns Architectures
Hexagonal architecture, coined by Alistair Cockburn in 2005, centers domain logic, shielding it from infrastructure via ports and adapters. Ports are neutral entry points, with adapters depending on them, inverting dependencies to isolate the core. Onion architecture, by Jeffrey Palermo in 2008, similarly layers domain, application, and infrastructure, omitting explicit ports but maintaining inward dependencies.
Oliver compares these to layered architectures from domain-driven design (DDD), where presentation, business, and persistence layers interact, with business potentially depending on infrastructure. The key difference is dependency inversion, but terminology shifts obscure similarities. Spring applications historically embodied this: controllers (presentation/adapters), services (business/ports), repositories (persistence).
Yet, these models often yield complexity, with excessive folders for adapters, contradicting their goal of clarifying business logic. Oliver argues they answer the wrong question—focusing on technical separation rather than business cohesion.
Alternative Approaches: Prioritizing Cohesion and Encapsulation
Instead of technical layers as primary packages or modules, Oliver advocates functional decomposition, grouping by business slices (e.g., order, customer). This avoids scattering related elements across layers, akin to organizing furniture by type rather than function.
In code, vertical slices encapsulate internals: controllers, services, repositories within one package, hidden by default visibility. Public interfaces expose only necessary surfaces, enhancing encapsulation over mere organization. For simple read-only scenarios, direct JDBC in controllers suffices, hidden from outsiders. Complex slices warrant internal abstractions.
This yields cohesive bases automatically decoupled, as inter-slice connections are minimal. Intrinsic complexity dictates accidental complexity—pragmatic layering per slice. Tools like Spring Modulith enforce this, using annotations for stereotypes (e.g., @AggregateRoot), integrating with IDEs to display architectural concepts beyond packages.
Trade-Offs, Tools, and Implications
Trade-offs include initial simplicity versus future adaptability: technical packages force public interfaces, risking violations, while functional ones hide more, supporting evolution. Oliver notes developers’ inclination toward technical structures stems from IDEs’ technology-centric views (e.g., source/main/java), lacking higher abstractions.
Spring Modulith and ArchUnit address this, verifying rules and visualizing modules. IDE integrations (VS Code, Eclipse) convey code via design stereotypes, reducing package reliance.
Implications favor cohesion-first design: functional decomposition aligns with change patterns, reducing scattering. It supports DDD aggregates and repositories naturally, without mandating architectures. As systems grow, this prevents tangled messes from entangled business logic, not just direct database calls.
In conclusion, reframing the question from decoupling infrastructure to fostering cohesive, change-resilient structures yields maintainable software, leveraging tools for integrity.
Links:
[PHPForumParis2022] Exploring DDD and Functional Programming Practices – Benjamin Rambaud
Benjamin Rambaud, an accomplished PHP engineer at ekino, delivered an engaging presentation at PHP Forum Paris 2022, inviting developers to explore Domain-Driven Design (DDD) and functional programming to enhance their craft. With a nod to the collaborative spirit of the event, Benjamin adopted a market-like metaphor, encouraging attendees to “pick and choose” principles from DDD and functional programming to enrich their PHP projects. His talk, informed by his role as a co-organizer of AFUP Bordeaux, offered practical insights into improving code quality and project communication, drawing from established methodologies while urging developers to adapt them thoughtfully.
Foundations of Domain-Driven Design
Benjamin opened by demystifying DDD, a methodology focused on modeling complex business domains with precision. He emphasized the Ubiquitous Language, a shared vocabulary that aligns developers, stakeholders, and domain experts, fostering clearer communication. By prioritizing domain logic over technical details, DDD isolates business rules, making code more maintainable and expressive. Benjamin illustrated this with examples from his work at ekino, showing how DDD’s strategic patterns, like bounded contexts, help developers encapsulate business logic effectively, reducing framework dependency.
Leveraging Functional Programming
Shifting to functional programming, Benjamin highlighted its synergy with PHP’s multi-paradigm nature. He introduced concepts like pure functions, immutability, and value objects, which enhance testability and predictability. By integrating these principles, developers can create robust, error-resistant codebases. Benjamin drew from his experience with Drupal, demonstrating how functional programming complements DDD by isolating domain logic from framework-specific code, allowing for greater flexibility and maintainability in PHP projects.
Practical Implementation and Hexagonal Architecture
Delving into practical applications, Benjamin advocated for hexagonal architecture as a cornerstone of DDD in PHP. This approach uses ports and adapters to decouple business logic from external systems, enabling seamless integration with frameworks like Symfony. He cautioned against rigid adherence to frameworks, referencing resources like Mathias Verraes’ blog for deeper insights into DDD patterns. Benjamin’s practical advice, grounded in real-world examples, encouraged developers to experiment with repositories and interfaces tailored to their project’s needs, fostering adaptable and resilient code.
Balancing Frameworks and Principles
Concluding, Benjamin urged developers to understand their frameworks deeply while embracing external paradigms to avoid being constrained by default configurations. He emphasized that DDD and functional programming are not rigid doctrines but flexible tools to be adapted contextually. By encouraging exploration of languages like Elixir or OCaml, Benjamin inspired attendees to broaden their perspectives, enhancing their ability to craft high-quality, business-aligned PHP applications through thoughtful experimentation.