domain-driven-designsoftware-designclean-architectureonion-architecturehexagonal-architecture

domain driven design ports and adapters


I am new to DDD and I am trying to apply it with Hexagonal architecture. I have the following scenario:

and third party REST API that I need to call before persisting the user to the repository

So I am trying to implement it using ports and adapters, so I have an interface in my application service layer that represents the third party functionality and I have the concrete implementation of that API calling exist in infrastructure layer as the following image

enter image description here

As you know this interface should take some params and returns specific type, my question is where should I put the types of these params and returned type, should be exist in the infrastructure layer or inside the application service layer?

for example I have the following interface:

class GetSomeDataInput{
  customerId string;
  userName string;
}

class GetSomeDataResult {
  userBlocked boolean;
  userAvailable boolean;
}

interface IThirdPartyAPI {
  getSomeInfo(GetSomeDataInput input): GetSomeDataResult;
}

As you can see the method should take specific param with specific type and return also specific type, and these classes should be implemented in both the caller side which is application service and also on the receiver side which is the concrete implementation so where should I put these types in infrastructure layer or inside the application layer or put them in a shared directory that could be accessed by both

Sorry I just wrote some pseudo code to explain my question, thank you.


Solution

  • Notice that your question applies to many different architectural styles (DDD, onion, hexagonal, clean, layered). The reason is that the question is actually a fundamental concept in OOP, which is the concept of Interface, and where languages like C# have created some confusion by introducing the keyword interface.

    What I mean by that is that a C# interface is not the same as the concept of Interface in all these architectural styles, also known as Contract. As you found in your case, the C# interface defines only one part of the contract. The full contract also contains all the input and output types and optionally custom Exceptions.

    Once you see this distinction, it is obvious that all the types used in the contract must be defined in the same place, as they are part of a single unit.

    In ports and adapters, onion, etc. the full contract would belong to the Core. In a layered architecture, the full contract would belong to the Data Access Layer.

    The advantage of Ports and adapters over layered is that all the names that appear in the contract belong to the Core/Domain, so they align with what domain experts will understand, making the contract a lot more readable. And the translation of these names to technical names which depend on the adapter technology is an internal concern of the adapter itself.