Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Domain service injecting into domain entities

I'm learning about Domain-Driven-Design and I'm a little confused about entities and injecting domain services into them. I have found this blog and conclusion is that injecting services into entities is a bad idea. I partially agree with that, but what to do in this case: I have User entity which is an aggregate root, which has Password value object in it. It look like this:

Password value object:

public class Password  
{  
    public string Hash { get; private set; }

    public string Salt { get; private set; }

    private readonly IHashGeneratorService _hashGeneratorService;

    public Password(IHashGeneratorService hashGeneratorService)
    {
        _hashGeneratorService = hashGeneratorService;
    }

    public void GenerateHash(string inputString)
    {
        //Some logic

        Salt = hashGeneratorService.GenerateSalt();
        Hash = hashGeneratorService.GenerateHash(inputString);
    }
}

User entity:

public class User
{
    public Password Password { get; private set; }

    public User(IHashGeneratorService hashGeneratorService)
    {
        this.Password = new Password(hashGeneratorService);
    }
}

In this case if I create User entity via factory I need to provide IHashGeneratorService implementation to factory constructor or Create() method. After that if my factory is used by, for ex. SomeUserService I have to provide implementation (ex. via ctor injection) to it. And so on... Honestly it smells form me, as lot of my classess are dependent on hash generator service implementation but only Password class uses it. And it also breaks SRP principle for Password class as I assume.

I've found out some solutions:

  1. Use service locator. But it also smells as it's an anti-pattern and it is hard to test and manage entities if we use it.

  2. Implement hashing alghoritm directly inside Password methods.

  3. Stay with that what I have :) Cons are mentioned above, pros are that my classess are easier to test as I can provide mocked service instead of full implementation.

Personally I tend to refoactor my code to second solution as it does not break SRP (or it does? :)), classess are not dependent of hashing service implementation. Something more? Or do you have another solutions?

like image 964
Mad Max Avatar asked Feb 13 '23 23:02

Mad Max


1 Answers

I am quite new to DDD, however I belive that hashing passwords is not a concern of the domain, but a technical concern, just like persistence. The hash service should have it's interface defined in the domain, but it's implementation in the infrastructure layer. The application service would then use the hash service to hash the password and create a Password instance (which should be a value object) before passing it to the User aggregate root.

There might be cases where an aggregate has to use a service like when the dependency resolutions are very complex and domain-specific. In this case, the application service could pass a domain service into the aggregate method. The aggregate would then double-dispatch to the service to resolve references.

For more information you can read the Implementing Domain-Driven Design book written by Vaughn Vernon. He speaks about this around page 362 (Model Navigation), but also at a few other places in the book.

like image 94
plalx Avatar answered Feb 28 '23 13:02

plalx