var blog = new ThoughtStream(me); RSS 2.0
 Friday, July 11, 2008

Earlier this week, I was doing a training session with my current team, building a sample Org Chart application. One of the user stories we were working with, talked about assigning managers to department and had the following acceptance criteria:

  • When assigning a manager to a department, ensure that they are an employee of that department, and remove them from their old department

The basic code that we came up with worked well and was encapsulated into a service object in the domain.

public class AssignmentService
{
    
    private IDepartmentRepository _repository;
 
    public AssignmentService(IDepartmentRepository repository)
    {
        _repository = repository;
    }
 
    public void AssignManagerToDepartment(Employee manager, Department assignedDepartment)
    {
        Department previouslyAssignedDepartment = _repository.GetDepartmentForEmployee(employee);
        if (previouslyAssignedDepartment != assignedDepartment)
        {
            previouslyAssignedDepartment.RemoveEmployee(manager);
            _repository.Save(previouslyAssignedDepartment);
        }
 
        assignedDepartment.AssignEmployee(manager);
        assignedDepartment.AssignManager(manager);
        _repository.Save(assignedDepartment);
    }
    
}

Problems

At first glance, this code seems simple enough, but we quickly ran into a problem when we started coding for another story and acceptance criteria.

  • When creating a department, allow a manager to be assigned

Off-hand, this seems like a very simple situation. We'll just call the AssignmentService object after we create the Department. However, there's a large potential problem with this - the AssignmentService handles the entity persistence for both of the departments that were changed, when the manager is assigned. With that in mind, the developer working on the new requirement would have to ensure that the department is created with all of it's required fields and information before calling this service object. If the developer allows the manager to be assigned before the department's info has been completely filled in, we may accidentally allow an invalid state for a department object when calling the AssignmentService. Since the AssignmentService tries to save the department being assigned, we may also have created an semantic coupling between the department creation process and the AssignmentService - the developer needs to know that the AssignmentService will save the department. If they don't know this, they may try to save the same entities more than once, may try to save an invalid state, etc, etc, etc.

Unfortunately, we didn't have time to fix the problem during the training session - we had to stop the training almost immediately after we discovered this issue. I've got a few ideas running around in my head, on how to fix this, but I'm not 100% sure that I like any of them.

Possible Solutions

First and foremost, though, it's becoming rather apparent to me that we want to avoid entity persistence calls from within the domain service objects. This essentially means that the AssignmentService object would have to return the assigned department, and the 'previously assigned department' objects, so that the coordinating presenter could save them both. That seems a little odd, if you ask me.

One of my coworkers suggested that we allow the service to save the previously assigned department, since that is an self-contained operation in the method (the method loads the department, modifies it, and saves it) and then return the assigned department so that the presenter can save it. This option seems a bit better off-hand, but I'm still worried about the possible side effects of the AssignmentService saving the previously assigned department.

Questions

What are your thoughts on this situation... How would you solve the dilemmas that I'm pointing out? Is there a better design for the model that would eliminate this problem and make the department persistence more obvious, without having to 'know' when it is persisted?

Is the idea of not allowing entity persistence from a domain service object valid? Should we go with allowing the self-contained operations to persist the entity in that operation?

Or ???

Friday, July 11, 2008 7:23:46 AM (Central Standard Time, UTC-06:00)  #    Comments [3]. Trackback 
Tags: .NET | Analysis and Design | Data Access | Domain Driven Design | Model-View-Presenter | Principles and Patterns | Refactoring | User Stories

Friday, July 11, 2008 8:47:05 AM (Central Standard Time, UTC-06:00)
Personally I avoid domain services talking to infrastructure, but in your case if you are using an ORM with a unit of work then are the calls to Save on the repository for existing objects just for clarity (or because the repository does verification).

On the validation angle, you say "we may accidentally allow an invalid state for a department object when calling the AssignmentService". In many cases this is true, but you might want to consider viewing "saved" or not as just another state for an Assignment. So saving an "invalid" Assignment is fine, but before it can become Active you do some validation.

Just a couple of thoughts.
Friday, July 11, 2008 10:19:54 AM (Central Standard Time, UTC-06:00)
@Colin

"avoid domain services talking to infrastructure"

do you mean just persistence, or all-together (reads and writes)? I think I agree with avoiding persistence calls in services (is still a lingering question, thoug). There are some real needs for letting a service read data from a repository.


Saving an invalid state, but not active:

That's an angle I have not thought for a long time. A few years ago I worked in a place where an IsActive field was used in a similar, but not quite the same way. My biggest concern would be enforcing IsActive throughout the system. All of the devs needed to know and understand what this means and how / when to use it properly (which is a good thing, of course. devs need to be trusted with that level of responsibility, or they shouldn't be on the team). In that company, though, it turned into a nightmare trying to remember when a non-active entity could be loaded and used.

Are you currently using IsActive in this manner? I'd like to know if it actually can work out the way it's intended to work.
Wednesday, July 16, 2008 1:56:36 AM (Central Standard Time, UTC-06:00)
"do you mean just persistence, or all-together (reads and writes)? I think I agree with avoiding persistence calls in services (is still a lingering question, thoug). There are some real needs for letting a service read data from a repository."

Personally yeah I avoid that as far as possible, to be honest I would prefer any repository calls to be outside the domain as far as possible.


"Are you currently using IsActive in this manner? I'd like to know if it actually can work out the way it's intended to work."

On my last project we did, entities would move through a variety of states. Definitely requires the rest of the system to be aware of the states (or for the other parts of the system to call back into the entities to ask if they are ready for use in case X) and there are alternatives such as having seperate classes for each state (e.g. ActiveAccount/PendingAccount).

There was an ALT.NET thread on this second approach quite a while back, if you want i'll try to dig it out.
Comments are closed.
Navigation
About Me
View Derick Bailey's profile on LinkedIn

Send mail to the author(s) Contact Me
Archive
<December 2008>
SunMonTueWedThuFriSat
30123456
78910111213
14151617181920
21222324252627
28293031123
45678910
About the author/Disclaimer

Disclaimer
The opinions expressed herein are my own personal opinions and do not represent my employer's view in any way.

© Copyright 2008
Derick Bailey
Sign In
Statistics
Total Posts: 91
This Year: 91
This Month: 0
This Week: 0
Comments: 40
Themes
Pick a theme:
All Content © 2008, Derick Bailey
DasBlog theme 'Business' created by Christoph De Baene (delarou)