0

I have a use case of scheduling a person to some work for some time range. Eg. A service for assigning a person A to work for time range X to Z in location C.

The only constraint it has, is one person cannot work on 2 things at same time. Eg. if person A is assigned to work in time 2019-07-21 to 2010-07-25, then person A cannot be assigned to any other work in that time. Eg. Person A for time range 2019-07-23 to 2019-07-27 should not be possible.

I am trying to make a service for it using domain driven design which would assign a person to some work. The entity I thought would be something like:

class Assignment {
    PersonId,
    startTime,
    endTime,
    location
}

Now, I wanted to make sure that if I found a entry in my database for Person A in some time range, then the call to create an entry for Person A in time range that is overlapping with the existing ones should fail.

Since, I am using CQRS model with DDD, so I don't want to make a query to my database asking for all the assignments for that person. This may not always be recent data because of eventual consistency in CQRS model. I know in my primary key, PersonId would be there but I am not sure how can I use start and end time in it.

Any suggestions what I can do to achieve my goal for this? Is doing DDD and CQRS not a good idea in this? Or there is a better way to model this entity so that I can achieve my goal.

1 Answer 1

2

The only way to ensure that a single Person can not be given more than one Assigment for a given time-span is to query for all ranges in which that Person is currently assigned work and calculate the invariant. That is, it is a requirement of your invariant that we have full knowledge of the time-spans for all current assignments. Querying your command side cannot be eventually consistent or invariants cannot be enforced. Period. That said, there is plenty of room for some optimization here.

The most obvious optimization is to add another invariant: a Person cannot be given an Assignment with a startTime in the past. This will greatly reduce the amount of data with which we are working (the effect is that you will no longer need to load any related Assignments with an endTime in the past).

A second optimization may be to internally "flip" the representation of available time-spans within each Person. So instead of storing a list of Assignment (unavailable time-spans), we store a list of UnassignedTime (available time-spans). Depending on how many Assigments you expect each Person to have at a given time and what other invariants may exist, the above (or some form of it) may be an option as well.

The last thing I would like to mention here is that this invariant needs to be placed on your Person entity (or some other slice of it e.g. Worker) because of the reasons outlined in my first paragraph -- whatever entity is getting assigned work must have knowledge of all of its current work. Again, depending on the details of your domain, the above makes the existence of the Assignment entity as your describe it unsuitable (as it has no invariants that it, itself, can enforce).

At a high level, I would expect the program flow to be something like:

// within AssignWorkCommandHandler or SchedulingService method

var person = people.Find(cmd.PersonId);

person.Assign(cmd.StartTime, cmd.EndTime, cmd.Location); // may throw

people.Save(person);

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.