Ilan Y
Ilan Y

Reputation: 107

Aggregate root and value object outside of aggregate

I have an aggregate root "Car" A car has a list of value objects "Wheels" containing "Wheel" objects. Since a car should not exist without wheels (at least according to our business logic), in order to construct a car is this valid in proper domain driven design:

double radius = 17.0;
List<Wheel> carWheels = new List<Wheel>();
carWheels.add(new Wheel(radius));
Car aCar = new Car(carWheels);

My question is basically, is it good practice to instantiate value objects outside of an aggregate root in order to construct an aggregate root (passing value objects in constructor). I don't want to create an aggregate root in an invalid state and would like to follow best practices. If the above code is not best practice, how should it be done?

Upvotes: 1

Views: 1267

Answers (3)

gseric
gseric

Reputation: 649

In this concrete example, I would give radius to Car's constructor and let it build wheels by itself. That way you would hide instantiation details from your client's code (less knowledge outside of your aggregate) and your client would not be affected by internal changes of Car aggregate.

You should prefer building aggregates in only one step/operation/action. If it's not just one step, your aggregate is inevitably showing some details of it's internal structure.

Upvotes: 1

dmusial
dmusial

Reputation: 1564

IMHO it is neither a bad practice nor a good practice. All depends on the actual domain which you are trying to model. It might make sense to create those VOs outside the aggregate in some cases and in others it will just open up your domain for malicious usage. DDD forces you to forget a bit about technical problems and bad/good practices in order to focus on the actual domain:

  1. Would it make sense in any scenario to create a car with 26 wheels? Your example model allows that
  2. Whould it make sense in any scenario to create a car with 4 wheels, each having different radius? Your example model allows that
  3. Whould it make sense to create a wheel with radius 17.3284546? Again, your model allows that to happen

Therefore, in my opinion for the example which you've shown, it might be better to handle those invariants inside the aggregate itself because you can nicely constrain the number of things than can be done to car and wheels when both are created. However, that comes from a closer look at the domain itself rather than relying on widely known good or bad practices. Just to reiterate, there will be cases in which you'll be better off by creating VOs outside the aggregate. All depends on the domain.

Upvotes: 4

Yugang Zhou
Yugang Zhou

Reputation: 7283

I like this approach. In test cases, we could inject stub/mock Wheels to Car.

I would introduce a CarFactory if there are complex business constraints in the construction of wheels or car.

Upvotes: 1

Related Questions