DDD - Invariant enforcement using instance methods and a factory method

134 Views Asked by At

I'm designing a system using Domain-Driven design principals.
I have an aggregate named Album.
It contains a collection of Tracks.
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?

1

There are 1 best solutions below

8
On BEST ANSWER

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.