DDD and getting additional information in a domain class

325 views Asked by At

I think I've read 16,154 questions, blog posts, tweets, etc about DDD and best practices. Apologies for yet another question of that type. Let's say I have three tables in my database, User, Department, and UserDepartment. All very simple. I need to build a hierarchy showing what departments a user has access to. The issue is that I also need to show the parent departments of those that they have access to.

Is it best to have a GetDepartments() method on my user class? Right now I have a user service with GetDepartments(string userName), but I don't feel like that is the optimal solution. If user.GetDepartments() is preferred then how do I get access the repository to get the parent departments for those that the user has access to?

Don't think it matters, but I'm using the Entity Framework.

public class User
{
    [Key]
    public int UserId { get; private set; }

    [Display(Name = "User Name")]
    public string UserName { get; private set; }

    [Display(Name = "Email")]
    public string Email { get; private set; }

    [Display(Name = "UserDepartments")]
    public virtual ICollection<UserDepartment> UserDepartments { get; private set; }

    public List<Department> GetDepartments()
    {
        // Should this be here? and if so, what's the preferred method for accessing the repository?
    }
}
1

There are 1 answers

1
Alexey Raga On BEST ANSWER

DDD is more about the behavior, which also mean it is TDA (tell, don't ask) oriented.

Normally you structure your aggregates in a way that you tell them what to do, not ask for information.

Even more, if some extra information is required by the aggregate in order to perform its behavior, it is typically not their job to figure out where to get this information from.

Now, when you are saying that your User aggregate has GetDepartments method, it raises a bell. Does the aggregate need this information in order to perform any kind of behavior? I don't think so, it is just you wanting some data to display.

So what I see here is that you are trying to structure your aggregates against your data tables, not against the behavior. This is actually #2 error when applying DDD (#1 is not thinking about bounded contexts).

Again, aggregates represent business logic and behavior of your system. Which means that you don't have to read from aggregates. Your read side can be done much easier - just make a damn query to the DB.

But once you need to ask your system to do something - now you do it through aggregates: AppService would load one from the repository and call its behavior method.

That's why normally you don't have properties in your aggregates, just methods that represent behavior.

Also, you don't want your aggregates to be mapped to the data tables anyhow, it is not their job, but the job of repositories. Actually, you don't want your domain to have dependencies on anything, especially infrastructure.

So if you want to go for DDD direction then consider the following:

  1. Structure your aggregates to encapsulate behaviors, not represent data tables
  2. Don't make your domain dependant on infrastructure, etc.
  3. Make repositories to be responsible to load/save aggregates. Aggregates themselves should know nothing about persistence, data structure, etc.
  4. You don't have to read data through aggregates.

Think of #4 as your system has two sides: the "read" side when you just read the data and show them in the UI, and the "command" side when you perform actions.

The first one (read) is very simple: stupid queries to read the data in a way you want it. It doesn't affect anything because it is just reading, no side effects here.

The second one is when you make changes and that is going through your domain.

Again, remember the first rule of DDD: if you don't have business logic and behavior to model then don't do DDD.