0

Following the hexagonal architecture and package design you will have somewhere an entry point reaching to your core functionality. Often this is done by using a facade.

To hide the core logic from outside i usually pass DTOs into that facades. For example imagine an File Import module which has the following facade method

public importFiles(FileImportDTO $fileimport) : FileImportResponseDTO

The FileImportDTO belongs straight to the fileImport module because it is obviously a part of it.

Lets imagine another module in my application called User with an UserFacade with the following facade method

public getUserData(UserDTO $user) : UserResponseDTO

Also this case is clear since the DTO obviously belongs to that module.

But what if i have to mix both? Lets imagine i want to get the imported files for a user. How to implement this in a proper way? The nearest solution to me would be

a) extend the ImportFacade

public function getImportsForUser(UserDTO $user) : UserResponseDTO

First i would extend the UserDTO having an field for its uploads. In this solution i am a bit unhappy about having a foreign Model (UserDTO) passing to the imports. That would mean: No File import module without the user module and vice versa.

b) extend the UserFacade

public function getImportsForUser(UserDTO $user) : UserResponseDTO

Here i would also expand the UserResponseDTO with an extra field called imports ... anyway. Also this solution seems to introduce dependencies and it feels also wrong to ask something about imports in a user facade ...

So, what is to most clean solution to this? I feel comfortable with neither of those.

Is it a good idea to pass a DTO from a foreign module to another module and declare it just as "its okay to have this dependency now" or should a translation from on model to another always be done by the business model for example?

Best regards

Jim Panse
  • 338
  • 3
  • 11

2 Answers2

1

A couple of thoughts.

1) Your modules are not of the same level. User module is in domain space, while Upload module seems to be in technical space. Applications should be split into modules based on domain features, not technical features. Therefore, if you have three use cases: fetch user data, import user file and fetch user imports, all of them belong to the user module, and the user module may use import module as implementation details. Import module should be purely technical and know nothing about users or other domain entities. That way it can be reused not only for users, but for any other domain entities which need importing functionality.

2) Your design is very procedural. You basically have C style procedures and functions which take data structures, do something with them and return other data structures. Try combining data with logic - encapsulate data and expose behaviour. Don't use DTOs, they were designed for a different purpose - it's wrong to use them like that.

Vytautas
  • 111
  • 2
  • Thanks for your great response! Do you think, the anemic model here is also true if both facades were real different domain spaces? I mean, i can't imagine "communicating" between two domains should involve any logic between the passed around objects ... further: where do you think, should something like the import module take place if its not a separate domain? – Jim Panse Jun 02 '20 at 06:47
  • If two subdomains need to communicate (assuming it's not an event driven architecture and it's not a distributed system), either one has to depend on the other, or there has to be some object outside of both domains, coordinating them. In either case, it would be dependence on subdomain objects with logic, I don't see why not. However, try to define your boundaries such that your modules are as autonomous and need to communicate as little as possible. If they tend to communicate a lot, maybe the boundary is wrong. And the import module could be a separate package, or a separate library. – Vytautas Jun 03 '20 at 19:34
1

DTO's are the words in a conversation following some Protocol.

From this viewpoint a DTO doesn't belong to either party. It belongs to the Protocol.

If both sides of that communication are written in the same/compatible languages then it is possible to have a single library that expresses those DTOs (and helper functions) and share them. Sometimes that isn't possible so the DTOs will be defined twice, and both sides will need the appropriate logic for converting them to/from bits over a communication link.


That being said, if these functions exist within the same process space, then DTO's are the wrong solution to the problem. Consider making them actual domain objects comprising both the state, and the behaviours that can be used with them.

This applies equally for your business logic, as it does for the technical implementations. They just have different domains. The Business Domain being implemented in terms of the Technical Domains.

Kain0_0
  • 15,888
  • 16
  • 37