Reputation: 1011
I am going to create a spring boot application following the best way of hexagonal architecture.
I found many examples, each one implement the hexagonal differently. I have some questions I need to understand:
Assumptions:
I want to have three layers: domain layer, infrastructure layer, application layer
Questions:
Ports and use cases: these are interfaces and they should exist in domain layer ?
Adapters: This is the implementation of ports interfaces and should be in the infrastructure layer ?
Implementation of use case interface:
3.1 This should be in which layer ? application layer or infrastructure
layer ?
3.2 This is the equivalent of spring service (annotated with @service streotype) ?
3.3 This should call ports implementations (adapters) as attributes or the inverse ?
Upvotes: 0
Views: 4727
Reputation: 4754
I am going to create a spring boot application following the best way of hexagonal architecture.
The 1st thing you have to take care of is that you will have to have a module (project) for the app (the hexagon) where you shouldn't use Spring Boot.
I want to have three layers: domain layer, infrastructure layer, application layer
Hexagonal Architecture (HA) doesn't prescribe layers, you can have whichever you want. The important thing is distinguish 2 zones: the hexagon and the outside.
The golden rule is that the hexagon doesn't depend (at compile time) on the outside.
Here there is a naming issue:
So in your case:
Ports and use cases: these are interfaces and they should exist in domain layer ?
Driving Ports are interfaces with the contracts (methods signatures) of the functionality that the hexagon offers to the outside (infra layer).
Use Cases are the implementation of driving ports interfaces.
Both should exist in the application layer, but don't expose use cases implementation to the outside (infra layer).
Adapters: This is the implementation of ports interfaces and should be in the infrastructure layer ?
It depends on the kind of ports: driving or driven.
Driving adapters are in the outside (infra layer) but they don't implement driving ports. They call the driving ports functions. For example, a REST controller.
Driven adapters are in the infra layer also. They implement the functions declared in the driven ports interfaces. For example a database adapter.
Implementation of use case interface:
3.1 This should be in which layer ? application layer or infrastructure layer ?
The use cases implementation should be inside the hexagon, in the application layer. It uses the domain layer, where domain entities exist.
3.2 This is the equivalent of spring service (annotated with @service streotype) ?
Yes.
3.3 This should call ports implementations (adapters) as attributes or the inverse ?
The use cases implementation call the functions declared in the driven ports interfaces. You inject the driven adapters (implementation of driven ports) at runtime.
Driven ports interfaces exist in the hexagon (either application layer or domain layer), so that at compile time the hexagon doesn't depend on the outside (infra layer).
For example, a driven port would be an interface for accessing the database, or for accessing an external service, or for sending messages.
Driven ports should be defined in terms of the application/domain concepts, in a technology agnostic way.
Finally, some useful links about Hexagonal Architecture:
https://hexagonalarchitecture.org/
https://alistaircockburn.com/Articles
https://jmgarridopaz.github.io/content/articles.html
https://www.youtube.com/playlist?list=PL1msPBH9ZGkhpANkreFA_teOnloVdLuCx
Upvotes: 1
Reputation: 68
We have followed a similar module structure as mentioned in the question & we had similar set of questions when we started. @denizg answered it well.
If we're following 3 modules domain, application & infra, then it is important to understand what goes where. As already mentioned,
domain - should have domain entities & domain services
application - this is the immediate layer to domain & should be used for interacting with domain. The ports are defined in this layer & provide details about what operations can be performed on the domain objects.
infra - this will be the outer layer & the adapters are defined in this layer which then interact with the application layer.
So far good but the confusion we faced was wrt the usecases. As mentioned by op, there are numerous examples which have usecases defined as interfaces. The confusion here is with regard to the naming as well where output ports are named as ports while input ports are often named as usecases.
This is where it's important to understand what purpose input ports serve. In Hexagonal architecture, the primary adapters wrap around an input port & use it to tell what application layer should do. So an operation that can be performed on the domain is indeed restricted by the input port & the primary adapters (Eg: Controller) delegate the call to application layer by injecting the implementation of input port, which is the Application Service.
In general a usecase represent the core business logic & encapsulates specific business scnearios or interactions. These are called by the application services to execute the business logic.
Upvotes: 1
Reputation: 952
Your assumption is one of truth, but there is no single truth. Some resources have 2 modules; infrastructure and application (including domain). I'll answer your questions based on your assumption.
Input/output ports and use-cases are part of application module, not domain module. Domain module has domain entities, value objects and domain services.
Adapters use ports by adapting them. Both input/output adapters must be in infrastructure layer. Use-cases are implementation of input ports, output adapters are implementation of output ports.
Actually, the "use case interface" term is wrong. Because use-cases are not interfaces, they are concrete implementation of input ports.
3.1 Use-cases must be in application module.
3.2 Yes, use-cases can be considered as the equivalent of spring services. Both use-cases and spring services have application logic inside. But application and domain modules must be technology independent due to the nature of hexagonal. So, don't use service annotation in use-cases. Make them bean in infrastructure module.
3.3 Input adapters use input ports to make an action application module. Input ports are injected to input adapters. Output ports are injected to use-cases.
Upvotes: 1