3

I am trying some DDD and I will try to describe in most simple manner what I have done.

Core project
The core project contains Entities, VO and domain services. For example I have User entity and UserRelation entity. I think we all know what is the User entity. The UserRelation contains information about how users are connected to each other like follow and connect(bidirectional follow). Because of that I have UserDomainService with stateless methods like Follow(user,user) and Connect(user, user).

public class User
{
    public string Name { get; set; }
    public string Username { get; set; }

    public void ChangeUsername(stirng newUsername)
    {
        ApplyEvent(new UserUsernameChanged(newUsername));
    }
}

public class UserRelation
{
    ctor(User1, User2, isBidirectional)
    public User User1 { get; set; }
    public User User2 { get; set; }
    public bool IsBidirectional { get; set; }
}

public class UserDomainService
{
    public UserRelation Follow(User user1, User user2)
    { 
        return new UserRelation(user1,user2,false);
    }
}

Repository Project

I am using NHibernate so I decided to not create such a project. Instead I am using NHibernate directly. For example, in my UI I get a user object from the DB, change it and then call session.Save(user).

The problem

If I want to do operation like follow I do this:

  • Get some info from DB
  • Call the Follow(user1, user2) from the service
  • Save the UserRelation object to the DB In the end the application code becomes a bit complex. Imagine if we want to use this code in 2-3 places and at some point we have to refactor it.

My solution
My solution is to create a ApplicationService project which will do the dirty work and force the consumer to use ApplicationService instead of using Entitties and Domain services directly

public class UserApplicationService
{
    ctor(UserDomainService userDomainService){}

    User GetUser(Guid id)
    {
        return NhibernateSession.Get(id)
    }

    public void Follow(Guid user1Id, Guid user2Id)
    {
        var u1 = GetUser(user1Id);
        var u2 = GetUser(user2Id);
        var userRelation = _userDomainService.Follow(u1,u2);
        NhibernateSession.Save(userRelation);
    }

    public void ChangeUsername(Guid user, string newUsername)
    {
        user.ChangeUsername(newUsername);
        NhibernateSession.Save(user);
    }
}

Is this application service good or bad? As you can see the new service act also as a repository so we can create a UserRepository class but lets skip that for now. What bothers me is the parameters in the two methods. They accept Guids and the service retrieves users from the DB. The other option is to pass directly User object. The ChangeUsername method is like the one from User entity + persistence.

Well, what do you think about this?

mynkow
  • 3,790
  • 4
  • 31
  • 59

2 Answers2

1

I personally don't see anything wrong, in fact this is how the company I work with has done it, as long as you abstract out the data access from that service it could be part of the business layer as a mediator between the data layer and the ui layer, it saves you from repeating yourself and making sure that any rules outlined for a certain operation fires.

Joakim
  • 2,185
  • 14
  • 20
1

My 2 cents.

DDD is applicable and make sense for large projects. You shouldn't apply it to the projects just because it is cool. By looking at the NHibernateSession I see you can get User by id. Well if NHibernateSession is responsible for that which other domain objects do you have? You don't have repository, why do you enforce an overheat of DDD?

OK, move on given you have a large domain it is not clear to me why would you create a new project to host the Follow functionality (it is nothing wrong with input GUIDs there). IMO Application Service layer should not be dealing with entities and infrustrucure, as it seems too low layer for this guy. Application service layer is responsible for the whole application, not the functionality of some domain objects. I noticed you have a _userDomainService which seems to be more relevant in your case. If moving the Follow functionality there doesn't make much sense, I would create another service at the Domain Services layer, calling it something like UsersManagerService or UsersDomainService

Lastly, if you are to implement a repository pattern, consider generic repository.

oleksii
  • 33,544
  • 11
  • 83
  • 149
  • 10x. I will try to follow and answer. My project is BIG :). The code above is pseudo code, not a working code and NHibernateSession is actually ISession. I create a new project because I have a section "The problem". I disagree with you about the application service. Also I did not move the follow functionality. The core project do not know anything about persistence and that is why we must use NHibernate directly OR create repositories OR create Application service to wrap such thing – mynkow Jul 21 '11 at 10:28
  • @mynkow, I didn't realise you have a large project. What I was trying to say is **Application layer** (depending on classification of coz) usually sits on top of the **Domain layer** and **Infrastructure layer**. To me the functionality you described belongs to the **Domain layer (Domain Services)**, which will use the infrastructure layer (ORM) as needed. – oleksii Jul 21 '11 at 16:12
  • Ok, I have a question. If we skip the application layer how the client will use the code for the Follow operation/command? authorizationService.IsAllowed("operation/follow", currentUser) -> u1 = repo.Get(user1)-> u2 = repo.Get(user2)->var relation = userService.Follow(u1, u2)-> repo.Save(relation). This is so much noise for the client. That is why I am trying to wrap everything in an applicationService which will do all those things above... – mynkow Jul 21 '11 at 18:04
  • @mynkow yeah you are spot on, to the client it should be very simple - one or two method calls would be ideal, which is done via the service incapsulation. Now you will need to decide where to put that service. – oleksii Jul 21 '11 at 18:51
  • Exactly. Imagine 2-3 other systems which want to consume Follow operation ;). 10x for the conversation :) – mynkow Jul 21 '11 at 19:07