1

We've got an aggregate root that has a position value so it can be ordered among the other aggregate roots; relative position is something that can change over time. We'd like to have a method that's "Move X before Y". Where should that method live?

I see a few places that could have that method:

  1. Aggregate Root: X.MoveAfter(Y). I'm not a fan of this because it'd require one aggregate root to have access to the repository that owns the aggregate roots to potentially change the order of other things

  2. Repository: Repository.MoveAfter(X, Y). The repository at least has access to all the data it'd need.

  3. Domain Service: Service.MoveAfter(X, Y). I lean towards this pattern, as it seems like the right place to make changes to multiple aggregate roots at the same time.

Which of these is correct? Is there another option I'm not thinking of?

asked Jan 24, 2020 at 19:57
1
  • I would personally go for the option 3. Commented Jan 30, 2020 at 14:49

2 Answers 2

2

I would like to put another option on the table:

It sounds like there is another concept hidden in your domain that could be named and represented as an aggregate itself.

Eg. if you are dealing with Containers in a shipping domain, the arrangement of containers where the position is relevant could be a ContainerArrangment or ContainerCluster etc., which could be modeled as an aggregate, holding references to other aggregates and managing positional changes (which are likely to have their own logic and invariants).

This is now where the business logic should reside.

Other than that, but in the same direction: you seem sure that your entites are aggregate roots. again - if positioning is relevant and calls for invariants violation checks - maybe your AR is not actually the root. judgement is up to you!

answered Jan 28, 2020 at 18:25
1

Where should you put behavior?

Your first choice should usually be in a value object, an entity or aggregate root (AR).

It’s the client that calls behavior on the AR. A client can call the repository twice with different id’s, to get two instances (x and y) of the AR. The client can then call the behavior on X and pass Y -> x.MoveAfter(y).

The implementation of the MoveAfter method would be something like:

class Foo
{
 ...
 public void MoveAfter(Foo other)
 {
 var oldOrder = this.order;
 this.SetOrder(other.order);
 other.SetOrder(oldOrder);
 }
 internal void SetOrder(Order newOrder)
 {
 this.order = newOrder;
 }
}

After invoking the domain functionality on the AR, the client instructs the repository to persist the changes on both objects.

A domain service can be created if you have behavior that doesn't belong to any value object or entity. These should be rare, as most behavior belongs to something.

Putting behavior in the repository is never a good idea. It moves business logic out of the domain where it belongs.

answered Jan 25, 2020 at 10:22

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

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

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.