2

I'm modelling a scheduling application and wonder how it could be avoided to update multiple aggregate roots (AR) in one transaction. I understand the fundamental problem of changing multiple ARs in one transaction, since it could cause a lot of conflicts. However, I don't see an alternative in my case.

The schedule looks roughly like this: Schedule

My current approach is that each task (T-1 ... T-6) is an aggregate root instance. Each tasks has a startTime, duration, endTime (can not be derived from startTime and duration), and dependentTasks. Furthermore each Resource is an aggregate root, as well. It contains a profile with times where the resource is available.

The following invariants apply:

  • Tasks on a single resource must not overlap each other.
  • Dependent tasks can only be scheduled after the planned end of the predecessor.
  • Tasks are prolonged if there resource is not available for a certain time ("break").

Let's say I want to move T-1, then

  • T-2 must be moved to avoid overlapping on Resource A
  • T-3, T-4 must be moved, because both can only start after T-1 is finished
  • T-5 must be moved to avoid overlapping on Resource C
  • T-6 must be moved, because it can only start after T-5 is finished, which in turn was already moved

So, a single move in the schedule (T-1) leads to changes in all other tasks! In the (good!) book "Implementing Domain-Driven Design" the generic answer is "use eventual consistency", but I think that wouldn't solve the problem, since moving tasks around is basically a transaction. I don't want a state where half of the tasks are already moved and the other half is in the old state because of a conflict.

In practice it gets even worse, because the schedule could be edited by multiple concurrent user, but maybe that is a story for another time.

Question

Is there a way to avoid modification of multiple task instances in one transaction? Or, is there at least way to reduce the number of modifications / conflicts?

1
  • 1
    It seems that (in your design) the aggregate root is actually the schedule.
    – user253751
    Feb 16, 2023 at 15:51

1 Answer 1

2

I don't want a state where half of the tasks are already moved and the other half is in the old state because of a conflict.

May I suggest you ask your users first what they want? I can imagine they have a different perceiption of this problem.

Resolving scheduling conflicts is often a non-trivial operation. It requires some time and thought-work. Hence it appears to be quite natural that on the way to a conflict-free schedule a user has to go through intermediate states where tasks overlap or dependent task are placed in the wrong order. This is especially true for an application where the conflicts are not resolved automatically, but manually by a user. Hence, expect users to have the requirement of saving intermediate states of a schedule, even if the schedule is not "complete".

So instead of trying to force users to have the schedule always conflict-free, provide an operation which enumerates all conflicts in the current schedule and helps users to resolve them one-by-one. The function can be reused to check if a schedule is conflict-free before it is "marked as ready", published, or used for something else. Or, your UI may display the schedule in red as long as there are conflicts, and in green when all conflicts are resolved.

Not surprisingly, this does not only make your application easier to work with, but also resolves your issue with the transactions, and will also make it easier to process concurrent changes by multiple users to the same schedule.

Thinking a step further, you may provide certain features in the application for resolving conflicts semi-automatically. Such operations will require a schedule with conflicts as input, something you would not have easily available by forbidding conflicts rigidly.

2
  • 1
    I like your approach of modelling conflicts explicitly. I didn't want moving only some of the affected tasks, because it might be hard to see what has been moved and why, if the root cause might not have been performed due to a conflict. But if everything would be moved regardless of conflicts, everything would be fine, as long as conflicts are obvious to the user.
    – deamon
    Feb 16, 2023 at 15:15
  • 1
    @deamon: yep, in case you have the resources to implement this, you could also determine the specific tasks causing a conflict, highlight them or display differnt kind of warning signs depending on the kind of conflict.
    – Doc Brown
    Feb 16, 2023 at 20:45

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.