Alan Marsh
Alan Marsh

Reputation: 61

Pass DTO interface into Domain Factory?

I am trying to apply the principals of DDD in my current project. I'll try asking this (long-winded) question with an example that will hopefully make sense.

When creating a new Member, my presentation layer calls MemberService.CreateMember(MemberDTO memberDTO) that is defined in an Application Layer.

My Presentation Layer has something like this:

MemberDTO member = new MemberDTO(); //Defined in Application Layer

member.Username = username;
member.Password = password;
//...etc

My Application Layer calls the following Factory method in the Domain Layer to create the member:

public static Member MemberFactory.CreateMember(string memberDTO.Username, string memberDTO.Password...)
{
  var member = new Member(); //Domain.Model.Member

  member.Id = GenerateIdentity();

  member.Username = memberDTO.Username;

  //... etc

  return member;
}

the Member is passed back to the MemberService (Application Layer) which saves it (Repository in Infrastructure Layer) and maps it MemberDTO (using AutoMapper) and passes it back to the Presentation Layer.

So, my Presentation Layer is setting values in the MemberDTO and then my Domain Layer (via Factory) is taking individual parameters and setting the values for the Member. Without the Factory it would be simple but I am generating the Id here. Would it be wrong to create a Domain Service instead to generate the Id? For example, change the the MemberService.CreateMember(MemberDTO memberDTO) method from:

public MemberDTO CreateMember(MemberDTO memberDTO)
{
   var member = MemberFactory.CreateMember(memberDTO.Username, memberDTO.Password); 
   //Domain.Model.Member

   SaveMember(member);

   //Pass DTO to presentation layer
   return Mapper.Map<Member, MemberDTO>(member);
}

To this:

public MemberDTO CreateMember(MemberDTO memberDTO)
{
   var member = new Member(); //Domain.Model.Member

   Mapper.Map<MemberDTO, Member>(memberDTO);

   //Add this method into a Domain Service to generate the ID and any other defaults
   Domain.MemberService.Initialise(member);

   SaveMember(member);

   //Pass DTO to presentation layer
   return Mapper.Map<Member, MemberDTO>(member);
}

Sorry for the long-winded question even though the answer could be a simple yes or no!

Upvotes: 3

Views: 2490

Answers (3)

nwang0
nwang0

Reputation: 750

The short answer: Yes, you can pass DTO objects to a factory.

The long answer: A domain object factory is responsible for creating fully initialised domain objects. However you are free to choose any form of input as long as you can provide required information. In this case, it is a matter of personal choice to have either methods in your factory: - public Member CreateMember(string userName, string password, ...) {...} - public Member CreateMember(MemberDTO memberDTO) {...}

From layering point of view, a domain object factory is a part of the domain model. Hence it may be used and depended by different objects in the domain model layer and the application layer. From what you described, the MemberService seems belong to your application (service) layer. You may find difficult dependency problems if you move the creation logic into it. For example, if a Booking domain object creates a Member domain object when it is confirmed, you could end up having the Booking object depends on the MemberService, which is not a good idea. The example is illustrated here: http://thinkinginobjects.com/2012/09/05/abstract-factory-in-domain-modelling

If we step back a bit and look at the problem with some perspective, I would like to ask what exactly the MemberDTO and MemberService serve your application. Is the DTO object used as a wrapper of a set of data fields? Is the MemberService simply delegating the create call to your factory and repository? If the answers are yes, it would be much simpler code if we get rid of the MemberDTO and MemberService all together and leave the presentation to call the MemberFactory and MemberRepository directly. I am making a lot of assumption here however, you may find the DTO and Service still desirable if your presentation layer and service layer are physically separated.

Upvotes: 1

Aaron Hawkins
Aaron Hawkins

Reputation: 2691

In relation to DDD, if this identity is not a domain identity (ie. what defines a User based on the Bounded Context), then it does not belong in your domain model. In most cases I have seen, the user name is the identity for the user in the bounded context and any generated ID will be done for the sake of database access. I suspect that this may be your case and, if I'm right, then the generated ID is an infrastructure concern and should be done by your repository implementation. Your domain should not have any concept of this generated ID.

On the other hand, let's say that user name is the identity for the user in your context and you wanted to generate that identity using some domain formula. In this case, generating the identity would be a domain service method because it doesn't really belong to an instance of any of your domain objects. The generated ID would then be passed into your factory and you would have:

public MemberDTO CreateMember(MemberDTO memberDTO)
{
   //Domain.Model.Member
   var member = MemberFactory.CreateMember(MemberService.GenerateUserName(), memberDTO.Password); 

   SaveMember(member); //Repository method?

   //Pass DTO to presentation layer
   return Mapper.Map<Member, MemberDTO>(member);
}

To summarize, the answer is no, it would not be wrong to create a domain service to generate the ID assuming the ID is the actual identity for the bounded context. In fact, this is what you should do. However, if the ID is not the identity of the user for the bounded context, then let your repository worry about how to generate IDs, access the db, and transform to/from your domain model.

Upvotes: 2

Davin Tryon
Davin Tryon

Reputation: 67316

I'm not sure about this question in relationship to DDD because I don't see a complex domain that needs the extra complexity. However, There probably is an argument to have the generation of the identity defined in another structure, but this is mostly to achieve single responsibility (SRP).

I suggest that you create an interface named IGenerateMemberIdentity. Then, you can isolate that complexity and test it. I think your intuition that this functionality does not belong in a factory is correct. If this is a complex routine, it doesn't seem to be about object creation.

However, for me, Initialize static methods seem like a code smell. Better to inject a dependency behind an interface that will provide that functionality.

To specifically answer your question. No, I don't think it is wrong. In fact, modeling complexity in order to preserve pure business functionality is what DDD is best at.

Upvotes: 1

Related Questions