Comparison of trinity architecture to hexagonal ports-adapters

Christos Tsakostas
Oregor
Published in
4 min readMay 12, 2019

--

1. Introduction

The Hexagonal Ports-Adapters architecture was invented by Alistair Cockburn in 2005. Today, it is one of the most prevalent architectures in the Domain-Driven Design (DDD) community.

Hexagonal Ports-Adapters

Since 2013, I have always struggled to promote Hexagonal in the projects I was involved in. Over the years though, I have frequently seen severe misinterpretations of the pattern regarding (a) the structure of the modules, (b) the dependencies between them, and (c) the appropriate locations and definitions of ports and adapters. Moreover, newcomers always get confused with the number six and the Hexagon. Symmetry does not necessarily exist in all cases.

Gradually, I came up with specific modules structures, dependencies, and terms applying the best DDD, and not only, practices. Eventually, I realized that Hexagonal is essentially Dependency Inversion, as far as the secondary adapters are concerned, with different naming: ports-adapters vs abstractions-details. Primary adapters are just clients of the API/Use cases. The Trinity Architecture emerged naturally as a way to balance the uncontrolled flexibility of Hexagonal with consistency, thus reducing subjectivity issues and error-prone decisions.

Details about the Trinity Architecture and its formation are provided in this article: https://medium.com/oregor/the-trinity-architecture-c89ed5743c1e

2. Comparison

The Trinity Architecture is based on the Dependency Inversion Principle. Therefore, the nature of the architecture is ultimately the same as Hexagonal’s (Onion’s and Clean’s too). Yet, there are subtle differences:

Comparison of Trinity to Hexagonal

2.1 Purpose and Categorization of Abstractions

How, exactly, do we define ports in Hexagonal? In Application Services or Domain model? And if in Application Services for public or internal usage? Which modules are responsible for defining primary or secondary adapters?

The questions above leave room for ambiguous decisions. With Trinity, there is no doubt: abstractions are defined in API, DOMAIN, and AUXILIARY. One can immediately recognize the purpose of the abstractions.

  • API: The public Application Programming Interface
  • DOMAIN: The domain model abstractions (i.e. repositories, etc.)
  • AUXILIARY: Neither API nor DOMAIN but necessary for the Application (i.e. monitoring, logging, etc.)

2.2 The API Detail

The API Detail (API implementation) does not have a direct equivalent to the Hexagonal. It is definitely not a primary adapter, as it does not drive the application - the API Clients drive. It is neither a secondary adapter, as it is not driven by the application.

2.3 Single Entry-Point

Trinity allows one and only one entry-point: the API. The user interface, REST services, incoming messages, webhooks, etc. use always the same entry points. Hexagonal, in contrast, allows several entry points (primary ports).

2.4 Protected Domain Model

The only direct client of the Domain Model is the API Detail. The API Clients use the API Abstractions (not the API Detail). Therefore, the domain model is protected and not leaked to API Clients.

2.5 Clear Terminology

The term API Clients (primary adapters) denotes clearly its role: Clients of the API. Domain Details and Auxiliary Details (secondary adapters) clearly separate the details into two major categories. More attention is usually given to Domain Details, like to the Domain Model. With this separation, AUX Abstractions and Details can be easily reusable, since they do not depend on the Domain.

2.6 APP

The application module, which includes bootstrap, composition, configuration, cross-cutting concerns, etc. is clearly depicted in the Trinity Architecture.

2.7 Recognizable in Code

One does not have to think about how to structure a project in Trinity. It is provided out of the box. Benefit? No hassle for architects. Developers familiar with Trinity can instantly recognize the architecture and start working from day one when joining a new team using it.

1:1 Theory & Practice

3. Conclusion

The Trinity is much more restrictive than Hexagonal, as it enforces best practices and specific modules structure. Hence, the main differences are:

  • Clear and purpose-driven terminology (API, AUX, DOMAIN)
  • Single-entry Point for all API Clients
  • Protected Domain model not leaking to API Clients
  • Reusable AUX Abstractions and Details
  • Project modules structure is provided out of the box with rigorous modules dependencies
  • Balances uncontrolled flexibility with consistency, reducing subjectivity issues and error-prone decisions
  • Easier code review
  • Better allocation of team members
  • Recognizable in code

4. Related Tools & Work

The Trinity Architecture

Medium article explaining the details of Trinity.

Trinity Demo

A demo of Trinity architecture for Java is available at Github.

Trinity Scaffolder for Java

It is possible to generate your own project in Java with the Trinity Scaffolder.

trinity4J

trinity4J is a set of Domain-Driven Design Libraries for Java Applications. It is a perfect fit for Trinity Architecture.

--

--

Christos Tsakostas
Oregor
Editor for

Electrical & Computer Technology Engineer / Software Architect