[VoxxedDaysBucharest2026] Ports, Adapters, and the Independence of Business Logic: George Patrașcu on Hexagonal Architecture in Practice
Lecturer
George Patrașcu is a seasoned software engineer at eMAG/CTO with more than twenty years of professional experience, including significant time in architectural leadership positions. Currently contributing to the Invoice and Payments platform team, George plays an active role in shaping internal developer guidelines and promoting sound architectural practices throughout a large organization characterized by hundreds of autonomous teams and diverse technology stacks.
Abstract
Within expansive microservices ecosystems featuring autonomous teams, frequent deployments, and heterogeneous technologies, business logic commonly becomes entangled with infrastructure specifics, yielding systems that are difficult to maintain, evolve, or understand. George Patrașcu presents Hexagonal Architecture—also recognized as Ports and Adapters—as a pragmatic methodology for protecting core domain logic from external dependencies including relational databases, RESTful services, event streams such as Kafka, and various third-party integrations. Grounded firmly in production realities at eMAG, the session provides balanced coverage of conceptual foundations, detailed C# implementation examples, testing approaches, and honest discussion of trade-offs encountered in practice.
The Challenges of Traditional Layered Architectures in Evolving Systems
Conventional layered architectures consisting of presentation, business, and data access tiers deliver initial value for straightforward applications. However, sustained growth across hundreds of teams utilizing varied languages (Java, .NET, Python, Scala), communication mechanisms (REST, Kafka), and continuous integration practices exposes fundamental weaknesses.
Business rules gradually permeate multiple layers: service classes reference persistence entities directly, controllers embed data access logic, and external service contracts influence domain models. Bounded contexts, a cornerstone of Domain-Driven Design, demand careful translation through anti-corruption layers, yet traditional designs frequently fail to maintain clean separation.
Resulting issues include duplicated business logic across backend-for-frontend components, mobile client platforms, and core services; severely compromised unit testing due to pervasive infrastructure dependencies; and cascading changes whenever external contracts, database schemas, or framework versions evolve. Simple folder structures offer no enforceable boundaries, while multi-module projects introduce tedious mapping layers that increase cognitive load.
Core Concepts of Hexagonal Architecture: Ports, Adapters, and the Application Core
Hexagonal Architecture fundamentally inverts dependency direction to position the domain model at the center. Business logic and associated domain entities reside within the core, depending exclusively upon abstract ports rather than concrete implementations. Input ports, implemented by driving adapters (REST controllers, message consumers), expose use cases to external actors. Output ports, realized by driven adapters (repositories, external clients), allow the core to interact with infrastructure without awareness of underlying details.
This structure adheres strictly to the Dependency Inversion Principle: high-level policy (domain) remains independent of low-level mechanisms (infrastructure). The hexagonal representation visually encapsulates the core, with ports serving as interfaces through which adapters connect. Domain objects and language remain pure, expressed in business terms rather than technical artifacts.
Flexible structuring accommodates varying scales: monolithic single projects for initial simplicity, separation of adapters by technical domain (isolating payment processors or external APIs), or evolution from modular monoliths toward independent microservices. This “build modular from the start” philosophy supports rapid feature development followed by natural service extraction when boundaries emerge.
Implementation Details, Trade-offs, and Testing Strategies
Practical development begins with domain modeling. For a rescue fleet management system, an AssembleFleet input port defines the primary use case contract. Implementation within a domain service orchestrates inventory retrieval and selection logic expressed purely in business concepts.
Driven adapters address external complexities: a Swappy client manages API pagination, performs type coercions (string passenger counts to domain integers), and implements anti-corruption filtering for inconsistent partner data. Custom domain annotations (@DomainService) facilitate integration with dependency injection frameworks without introducing technical concerns into the core.
Persistence strategies favor rich domain models mapped via ORM capabilities (e.g., shadow properties, complex types), minimizing dual maintenance of entities. This preserves core purity while leveraging framework strengths.
Testing follows clear separation: exhaustive unit tests exercise domain logic in complete isolation, while integration tests utilize fakes and mocks for adapters, verifying translation correctness without external system dependencies.
Trade-offs warrant careful consideration. The pattern excels with rich domain models containing substantial behavior but may introduce unnecessary indirection for straightforward query-dominant services. Hybrid approaches applying hexagonal principles selectively to complex logic paths, combined with CQRS separation or vertical slice organization, often prove optimal. The speakers caution against architectural dogmatism—context, team maturity, and problem complexity should guide application extent.
Architectural fitness functions, implemented via tools like ArchUnit, provide automated verification of boundaries even when AI assistance generates code.
Implications for Autonomous Teams and Long-Term Maintainability
Within large organizations featuring hundreds of developers operating with significant autonomy and minimal centralized control, Hexagonal Architecture strikes an effective balance. Teams retain freedom in implementation details while benefiting from consistency promoted through architecture guilds and shared guidelines. The pattern facilitates technology migration, incremental refactoring, and clear delineation of responsibilities.
By maintaining domain logic independent of infrastructure specifics, services demonstrate greater resilience to external changes—whether API contract updates, database platform shifts, or new integration requirements. This aligns naturally with trunk-based development, feature flag strategies, and high-frequency deployment practices, enhancing overall organizational agility.
Not every service necessitates complete hexagonal purity. Selective application targeting areas of highest coupling delivers outsized returns in testability, evolvability, developer onboarding speed, and long-term maintenance costs.