Search code examples
javaarchitecturemicroserviceshexagonal-architecture

Hexagonal architecture/Ports and adapters: Communication between adapters


I have read quite a few articles about ports and adapters. Considering communication, they all just speak about communicating between the different "layers" (domain, application, adapters) through ports.

But what is the correct approach when I want to communicate between two different adapters? For example, I want to get a document from Elasticsearch and enrich this document by a few values which are stored in S3?

I remember that a former colleague of mine said that it is ok when adapters communicate directly with each other (that is: call each other's public methods directly), without using ports. But is that really true ? Where can I find further information on that? And what would be the advantages/disadvantages of using ports for communication within a layer?


Solution

  • TL;DR

    Short answer, no you may not have adapters talking to each other.

    It does not really make sense in an hexagonal architecture. ;)

    I would not use ports to communicate the way you describe outside the domain perview, as it leads to having logic pertaining to the domain leaking in the sides of the hegaxon ( if I understood correctly your question)

    In an hexagonal architecture, you start from a call to a primary port, that will call any domain classes involved, which will turn to secondary ports to address needs that are outside of the domain concern (persistence, event propagation, so on and so forth).

    That being said, read on as to why ;)

    Long answer

    Let's get back to what precisely is an adapter. It is the implementation of a port ; a port being an interface defined in the hexagon, and defining :

    • for primary or driving port, what the domain can do, what services it exposes to the outside world
    • for secondary, or driven port, what services must exists for the domain to do its job

    Port are expressing all that in domain terms, that is, using the classes, dto, objects that are part of the domain

    Ports should be tailored to the domain/business needs ; they should not care about the underlying technologies (emphasis on the plural) involved (that being the point of the hexagonal architecture to begin with)

    So in your specific use case, it would make much more sense to me to have one port defining how to load your domain object, and it's adapter implementing the retrieval and mapping using both ES and S3 in the same adapter.

    If you need to mutualize some code on the ES or S3 part, you should do so in specific components ("repositories", so to speak) that you would inject in said adapter :)

    Nowhere in the hexagonal architecture it is stated that an adapter must be tied to a specific technology ; if so it would mean that your port is tied to a specific technology, which in turn defeats the purpose of this architecture.

    You may think of ports/adapters on the driven side as a kind of facade in front of a specific system serving the needs of the domain/hexagon.

    As such, it abstract away from the domain the specifics of the system addressing the concern involved (here, the fact that your domain object is persisted in two different storage systems)

    As for research I mostly read Alistair Cockburn on this :)

    The rest being a lot of applied knowledge with that architecture ;p

    Hope that helps, let me know if anything in my answer require more precision ;)