Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Persistent ignorant Domain Layer

My programming language is C#. I've got a question regarding persistence ignorance within my domain model.

Let's assume I have got a person class like so:

public class Person
{
    private string email;

    public string Email
    {
        get { return email; }
        set { email = value; }
    }

    public Person(string email)
    {
        this.email = email;
    }
}

Now, within my domain model, there is a rule that there cannot be two persons having the same email address. So when instantiating a new person, this needs to be validated as well as when changing email property. So I was wondering how you would solve such a validation within you persistence ignorant domain layer. What I currently do is using a factory pattern for person instantiation in which I inject a person repository. There I can search for other person with the same email address. Like so:

public class PersonFactory
{
    private static readonly IPersonRepository personRepository;

    public Person CreateNewPerson(string email)
    {
        Person personWithSameMail = personRepository.GetPersonByEmail(email);

        if (personWithSameMail != null)
            throw new ApplicationException("Email already exists.");

        return new Person(email);
    }

    public PersonFactory(IPersonRepository personRepository)
    {
        this.personRepository = personRepository;
    }
}

But using this solution, the check when changing the persons email address (which can be a valid business case) is still not covered. Furthermore the Person class still exposes a public constructor and by bypassing the factory, persons with duplicate email addresses would still be possible.

Any elegeant solutions to this?

P.S. To all data centric people: No, I don't want to validate dupe emails in the data access layer ;)

UPDATE:

Probably this whole question is obsolete anyways. Checking for duplicate emails in terms of a domain model context would always require "something" that is aware of all persons - a root. The "something" could be an address book, or the whole world containing all persons with email addresses. So maybe I am mixing up the programmers need of technically elegant solutions to problems, that exists only because of lack of a complete and well thought out domain model. Can this be the case here? That there is not just a person with an email address floating around in space (hey, space would be my aggregate root here ;) ) just for the fun of existence? But if this would be a real business case like an address book application, address book would be the aggregate root of person and thus could check for all persons in its internal collection to ensure that there is no duplicate email address.

like image 960
Chris Avatar asked Nov 04 '22 09:11

Chris


1 Answers

I'm not a DDD expert but my take on it is like this.

First of all, for me the biggest flaw in your design is allowing setters on the entity. That means that you can alter the state of your entity without the aggregate root knows about it. I would refactor it removing the setters and and letting just setting it through the constructor at the object creation.

Another point. Person entity should not do the validation of the email (in the form of checking if the email is already used or not), because it can only be aware of it's own state and related child entities if she is the root of the aggregate. Then you should have a reference to the repository from the entity which is for me the bad design. That's why you have used the factory I think.

I think the validation should first occur in the UI to fail as fast as possible. But it's not sufficient. When persisting your domain state you should enforce the rule that the Person has an unique email. I think that the validation should occur in the domain service for example called PersonRegistrationService that would have a reference to the IPersonRepository and before adding the person entity to its collection to persist, it would check first if the persons emails is unique. If not I would inform the user with an error and not add the entity.

What do you think ?

like image 110
Tomasz Jaskuλa Avatar answered Nov 15 '22 01:11

Tomasz Jaskuλa