Where should business logic go in a layered architecture

domain-driven-designlayersservicesvalidation

First of all, i'm not talking about validation in the sense of the nullability or length of a field like in this and this questions where we can use isValid() methods in business classes or an external Validator. However, my question is related to validate or not in business classes.
I'm using a layered architecture style with services consuming the datasource layer and interacting with the domain model.

Simplyfing the domain requirements, suppose I have Movies and Reviews, and Users can make only one Review per Movie.
So, a second Review is a valid object but the business rules should not allow the review to be completed.

So, i could do:

ReviewService >> addReview(review,movie)
  loggedUser = getLoggedUser()
  review = reviewRepository.searchReviewFrom(loggedUser,movie)
  if (review == null)
    reviewRepository.save(review)
  else
    // some mechanism to inform the error, it could be NotificationPattern

Or:

Movie >> addReview(review)
   for r in this.reviews
     if r.user = review.user
       throw ReviewAlreadyUploaded
   // if no expcetion is thrown
   this.reviews.add(review)

I think this oneReviewPerUser validation is a pure business rule, and should go in the business classes, in this case the Movie class. Thus the business rules are contained whitin the domain and no scattered between the layers.
However, if the lists of Reviews of the Movies are big in almost every case, this option implies query and instantiate a big number of Review object and iterate over all elements.

So assume that I choose option 1, I have to assure that every client that wants to create a review for a Movie must use the Service, because it may break the business constraint of 1 review per user if, for example, use directly the ReviewRepository.
This starts to sound like a layer of Services with all the business logic and an AnemicModel with Domain Classes being bags of attributes for carry data to and from the database.

Where is the line that separates the business logic that should be on Services from the one that should be on Domain Classes.

Best Answer

In a DDD (Domain Driven Design) application using a conventional layered architecture, business logic goes into the domain layer. Now, please note this layer does not only contain the domain entities (Movie, Review), but also domain services (like a ReviewService class) and repositories. So, ReviewService is a business class as well.

Your concern about every client having to use the appropriate business method (addReview) is not realistic. There is just no practical way to avoid a poorly written client class from violating business rules, if the developers don't stick to the rules of the chosen architecture. For example, if Movie has a getReviews() method (or a reviews property) which exposes a mutable collection of reviews, client code can always add an arbitrary review. And even if it's immutable, client code can always create the invalid Review in the database by directly using a repository.

In my opinion, it's best to have only relatively simple business methods in domain entities, and usually only for read-only operations. More complex business logic is best assigned to cohesive domain service classes. Otherwise, your entity classes will quickly become too big and complex. So, for example, a business operation that adds a movie review subject to business validation rules would be best put in a ReviewMaintenance domain service class, or even a ReviewCreation class if the "add review" operation is sufficiently complex.