Ports and adapters / hexagonal architecture - clarification of terms and implementation
inf3rno gave a good answer which clarifies the original question, but it may be useful to highlight some other uses for ports and adapters.
According to my understanding the port is an expression of your interface.
The port:
- Defines the exposure of the core's functionality (for 'incoming' ports)
- Defines the core's view of the outside world (for 'outgoing' ports)
The adapter:
- Is located outside the component (hexagon)
- Is used to ensure that the transport between port and the target happens in a way that satisfies the contract with the port's interface
- Is what you replace (using dependency injection) to test the hexagon
The port should accept the adapter and make sure that the adapter implements the interface. Then it should merely call the appropriate methods/functions on the adapter.
The port should be included in communication testing. In that case, what is 'mocked out' is the cores of two neighbouring hexagons (or a hexagon and a service) and test the port/adapter/adapter/port assembly.
For more information you can view the talk about Hexagonal Microservices that James Gardner and I gave at London's Skillsmatter Microservices meetup in July 2014.
I think it is pretty simple concept. You have the application core, which does not depend on anything outside of it. For example it does not depend on HTTP frameworks, database drivers, mailing frameworks, and so on... This core has a very specific interface depending on your problem domain, so the code of your application core should change only if your problem domain changes.
For example you have blog posts and you want to add categories to them. So the categories should flow through the entire system, from the HTTP communication to the databases by writing and vice-versa by reading.
Now what if you want to replace your MySQL database for example with MongoDB, because why not. It should not affect the core, because the application does still the exact same thing: it stores your blog posts and ofc. their categories and returns them on demand. So what you need is only a MondogDB adapter in this case, which you can use instead of your MySQL adapter.
What if you want for example a REST API, and not just a simple HTML page? It still does not affect your application core, so what you need is another adapter for REST communication.
So in my opinion your adapters should have specific interfaces defined in your application core, and the ports should communicate with the application core using these adapters. So in my opinion the ports do not necessary exist as classes, just the adapters, and their interface. This concept makes sense, because your application core won't be tightly coupled to the ports you want to use, just to the adapter interfaces you define. (There are multiple similar architectures by the way. Like clean architecture, onion architecture, which use the same concept with a different vocabulary.)
Someone at my work did a great internal presentation on this architecture. At the end, during question time, another colleague asked:
Isn't this just a layered architecture with a different name and drawn differently?
And, to be honest, that's true to a large extent. For many applications, a hexagonal architecture will be structured identically to a layered architecture, with a few specific details:
- There is increased discipline in defining interfaces between each layer (the ports), rather than calling impl to impl.
- There is a focus on "the core" (business logic) as being the most important layer, with all other layers (the adapters) being viewed as somewhat subservient.
- The focus on defining interfaces from the perspective of the core prevents the language of the adapters from leaking into the core. For example, if you're putting your persistence (e.g. Hibernate) into an adapter, then you should not have any @Entity classes in your core.
You can see that, even when doing all these things, it's still just a layered architecture, just with the boundaries between layers being quite strict and a focus on the central layer.
So, to specifically answer the question, you can understand ports and adapaters by recognising that ports are the interfaces into and out of the core, and adapters are just the implementation layers that are not the core.