2

Following this post https://stackoverflow.com/questions/21554977/should-services-always-return-dtos-or-can-they-also-return-domain-models and best practices in Software Arch suggestions by Martin Fowler

A Service Layer defines an application's boundary [Cockburn PloP] and its set of available operations from the perspective of interfacing client layers. It encapsulates the application's business logic

I have a problem doing so consider the following:

UserService {
     UserDto findUser();
}

UserService should be fine if used in the controller where I just need data only so dto is sufficient,

But here is the problem if I used this service in another service say e.g CustomerService I need the model itself the User object since the model should be managed by some persistence context

e.g

CustomerService {
     void addCustomer() {
           Customer customer = new Customer();
           User user = userService.fimndUser(xxx); // BAM compilation fails since findUser returns UserDto not User
           customer.setUser(user);
     }
} 

What would be best practises here should I 2 copies of findUser method with 2 different return types or 2 copies of UserService class one for controller use and other for service or core package use, Or should I implement some proxy pattern

  • The same Martin Fowler says (If I do recall well), that using DTOs between layers is overkill and make things too complicated. Why don't you simply use domain models and delegate the mapping to DTOs to the controller? Basically, is the only component that really uses DTOs as response model, – Laiv Nov 12 '19 at 11:29
  • IMO, Mapping itself is considered as a business logic code, Plus this would expose the model to the controller layer some would not see any problem with that since it won't be exposed to the consumer, But IMO this contradicts with the idea of Modularity – YouYou Nov 12 '19 at 11:50
  • Exposing the model to the controller is ok. The dependency keeps flowing from volatile code to a more stable one. The problem would be exposing the domain to these DTOs. Controllers are drivers and it's expected from drivers to transform inputs and outputs so that both elements (callee and caller) don't need to know about each other models or domains. It's not a service goal to generate DTOs for every possible consumer. That's the controller's concern. – Laiv Nov 12 '19 at 12:01
  • The opposite leads you to your current situation. Having to offer different response models for different consumers from code that is meant to be agnostic to these issues. – Laiv Nov 12 '19 at 12:05
  • 1
    I would consider the mistake here (a common one) to be having services depend on services - the service should just be an externally-facing abstraction from the controller and internally it should simply be a means of orchestration - fetch the data, populate and invoke the (pure) domain, return (or persist) the output. The service itself is NOT the business logic component. Its only injected dependencies should be interfaces for external dependencies like databases. – Ant P Nov 12 '19 at 12:32
9

A really simple rule of thumb is that you should only use a DTO object when you need to ... transfer data. That means use a DTO at the boundaries in your web API, or when you are sending the object on a message bus. Internally, just use your domain objects.

The only reason a DTO should exist is the limitations of the (de)serialization layers. Those need simple objects without complex logic.

Recommendation:

  • Use standard models in your services
  • Convert the model to a DTO in the controller (i.e. in your web application) just prior to serialization.
  • If you use asynchronous messaging, convert the model to a DTO just before pushing the DTO on the message queue

This allows you to use your services as you desire, and save the DTOs for when they are actually required.

|improve this answer|||||
  • While your point is very valid, I think it does not answer the question. – tom van green Nov 13 '19 at 14:17
  • The best practice is to not use DTOs in your service layer. Only use them at the edges. Without DTOs in the service layer, there is no conflict for what the OP wants. Or am I missing something? – Berin Loritsch Nov 13 '19 at 15:23
  • Ah, I think I get your point now ;) Do I understand you correctly that you are saying the service should not return a dto and that it should be the controllers responsibility to convert it to a dto? If so you could maybe update your answer to make this more clear, as I completely missed this point and thought you are discouraging OP to use dtos at all. Edit: Hmm, I can't change the downvote until you edit your answer... – tom van green Nov 13 '19 at 17:06
  • 1
    Edited, hopefully this is clearer. – Berin Loritsch Nov 13 '19 at 19:42
  • If you want to keep services/business logic independent of consumer, then it is always better to have at api level. Idea is to keep dto convertion at edge. – Imran Javed Jan 1 at 22:36

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.