I'm designing a system using Domain-Driven design principals.
I have an aggregate named Album
.
It contains a collection of Track
s.
Album
instances are created using a factory method named create(props)
.
Rule 1: An Album
must contain at least one Track
.
This rule must be checked upon creation (in Album.create(props)
).
Also, there must a method named addTrack(track: Track)
so that a new Track
can be added after the instance is created. That means addTrack(track: Track)
must check the rule too.
How can I avoid this logic code duplication?
Well, if Album
makes sure it has at least one Track
upon instantiation I don't see why addTrack
would be concerned that rule could ever be violated? Did you perhaps mean removeTrack
?
In that case you could go for something as simple as the following:
class Album {
constructor(tracks) {
this._tracks = [];
this._assertWillHaveOneTrack(tracks.length);
//add tracks
}
removeTrack(trackId) {
this._assertWillHaveOneTrack(-1);
//remove track
}
_assertWillHaveOneTrack(change) {
if (this._tracks.length + change <= 0) throw new Error('Album must have a minimum of one track.');
}
}
Please note that you could also have mutated the state first and checked the rule after which makes things simpler at first glance, but it's usually a bad practice because the model could be left in an invalid state if the exception is handled, unless the model reverts the change, but that gets even more complex.
Also note that if Track
is an entity, it's probably a better idea not to let the client code create the Track
to preserve encapsulation, but rather pass a TrackInfo
value object or something similar.