DDD Ports and Adapters with Onion architecture, what goes where?
G

3

7

trying to figure out some concepts and haven't been able to understand

What is a use-case in the Ports and Adapters architecture ?

What an implementation of a use-case would look like ?

What is a use-case concern ?

Where does it fit in the Infrastructure or Domain, it says it goes in the Application, well there is the Application Core and the Application Service which from my understanding are different ?

On the left side, the adapter depends on the port and gets injected a concrete implementation of the port, which contains the use case. On this side, both the port and its concrete implementation (the use case) belong inside the application;

https://herbertograca.com/2017/09/14/ports-adapters-architecture/#what-is-a-port

This quote confuses me ... because from what I understand a Primary Adapter can be anything that is asking for your business logic (it is interested in what you provide) WebAPI, MVC, Testing, ConsoleApp.

On the left side, the adapter depends on the port and gets injected a concrete implementation of the port which contains the use case.

So I assume that it refers to your business logic being injected in let;s say a WebApiController Constructor

On this side, both the port and its concrete implementation (the use case) belong inside the application;

So what ? who is this

application

Is it the WebApi ? or is the Domain ? also the use-case from what I understand is the implementation of my business logic, so for example the design would be something like this ?

Client :
WebApiController(IMyBusinessServicePort service)

Infrastructure :
ImplementingPrimaryAdapter : IMyBusinessServicePort { }
ImplementingSecondaryAdapter : ILoggingPort { }

Domain :
ImplementMyBusinessLogicService : IMyBusinessLogicService 

So WebApiController will use the implementation provided by ImplementingPrimaryAdapter and not something from my domain ? I don;t understand

please explain .

Gynaeco answered 13/9, 2018 at 21:22 Comment(0)
J
4

Hexagonal architecture doesn't say anything about the internal structure of the hexagon.

The use cases fit like this:

Driver ports are the use case boundary of the application (the hexagon). A use case interface would be a driver port. The implementation of the use case would be a class inside the hexagon.

What Alistair call application is not the DDD application layer, is the business logic as a whole, the hexagon, decoupled from technology. If you want a comparison with DDD layers, the hexagon would have to be splitted in two layers: application and domain. The ddd infrastructure layer would be the adapters outside the hexagon.

But hexagonal architecture doesn't say anything about DDD, they are different things. It's up to you how to fit DDD with hexagonal architecture.

I have written an article about hexagonal architecture, if you want to fix the concepts:

https://jmgarridopaz.github.io/content/hexagonalarchitecture.html

Hope it helps.

Jelle answered 13/9, 2018 at 21:41 Comment(2)
One question please, so if Driven Ports represent the Abstraction of 3rd party packages, libs, framworks ... and Driven Adapters are just implementation of those Ports. How is a Driving Port represented ? and who would Implement it?, is this where a mediatR would fit in ? just to throw the concert as fast as possible to Application ? So the MediatR is the actual Driving Adapter and let;s say a WebApi is the Driving Port ?Gynaeco
A driver port is implemented by the inside of the hexagon. An the implementation calls a drven port if it needs something from the outside world. I explain it in my articleJelle
A
1

There are some differences in implementation, depending on whether you use call-stack based programming or, for example, The Actor Model.

Next I talk about a case that is the closest to DDD and "C" part in CQRS: making changes to a system's state. "Q" part is simpler from the side of Hexagon: its complexity is mostly on the adapter's side.

As for me, I put vocabulary in the core of a Hexagon. It maps to the DDD Ubiquitous Language model and consists of immutable data structures with validation of business invariants on these data structures.

Next, there is a point of decision making. When you make a decision, according to Single Responsibility Principle, you should do only this. Not make external calls, IO, etc. So, you need some info to make a decision. When this info is gathered, in can be wrapped in a Command object. You pass it to a decision maker, which roughly maps to a DDD aggregate. It then either approves command and produces Event or Changeset (whether you do EventSourcing, or not), or a Rejection. Without any external calls. I.e. it doesn't use any Hexagon's ports.

What is left inside a Hexagon is a logic to gather external data, call a decision maker and process result. This logic can be modelled as a simple Finite State Machine and unit tested. This is what I call a Use Case in my Hexagon. Because this is the place, where data flows between ports and decision makers is coordinated. So, a Use Case uses Ports.

A Use Case instance gets created upon receiving of a business request on a Hexagon's primary port. There is a UseCase's FSM and executor, who actually calls secondary ports, receives their responses and advances the use case FSM.

A Use Case's processing flow can consist of the following steps:

  • Validate received business request
  • If invalid - format business response with error
  • If valid - prepare requests to secondary ports
  • Send prepared requests
  • Receive secondary ports' responses
  • In case of failure or timeout - format business response with error
  • If data gathered successfully, prepare Command for a decision maker
  • Call decision maker and get back Event/Changeset/Rejection
  • If rejected - format business request with error
  • If accepted - prepare another set of requests for secondary ports to execute the decision: persist to DB, send to MQ, launch rockets, etc.
  • Wait for execution of requests by secondary ports
  • If failed - format business response with error
  • If ok - format business response with success

So, a Use Case definitely belongs to a Domain, as it doesn't depend on implementations of adapters, but on their interfaces. And it forms a Domain's application layer.

It is useful to put a Use Case in a separate fragment of code, because this way this code would have a single reason to change - if, well, the use case changes. It is distinct from decision making logic or from Domain Values validation logic.

Affrica answered 14/9, 2018 at 18:48 Comment(0)
Y
1

Domain :

  1. ports (which connect the domain with infrastructure)
  2. application services
  3. domain services
  4. domain factories
  5. domain entities

Basically you don't leek any infrastructure concerns into your domain, you use abstractions.

Infrastructure layer, anything that can be subject to change, ORM, Caching, Logging, etc etc...

Yemen answered 1/8, 2020 at 14:27 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.