3

Let's say we have Book entity in our library. A requirement says:

Librarian may disable 'available' flag to books published before some year. For example, librarian may 'hide' some old books from being publicly available as they are rare.

This behavior is easily done with single SQL command. The method name for this behavior may be e.g. hideBooksPriorToYear().

But where to put this method?

  • if we put it in the Repository, soon it will be full of such methods; moreover, this is a business method, not a repo method.

  • we might fetch all old books and hide one by one, but this is slow.

  • we might create a business service for that, but that looks like anemic model again

  • we might put this method in a model, but I don't want to put sql there.

Any wisdom on this?

EDIT

Trying to clarify. When I try to move behavior to the entities methods, I found out that most of the business is not available without a repo. And I do not want to inject repo instance into the models. So my entities soon starts to be: 1) simple data objects, and 2) factories for entities/aggregates that are related to the model.

  • This could be a static method on Book, since it does not apply to a specific book in this case. But it sounds like the architecture could use some work first: ideally, SQL is separated from your domain models since it is implementation-specific. You should be able to swap out one SQL database for another or for NoSQL or a flat file without affecting your data models. – user22815 Oct 30 '14 at 19:14
  • Yeah, and in that sense it belongs to Service... and I am afraid soon we have a lot of such methods. I just can't see how I can decouple repo from the models in some cases. – lawpert Oct 30 '14 at 19:18
  • 1
    Perhaps there's a new concept to unearth here. Do libraries have "Book Visibility Policies"? – Darien Oct 30 '14 at 19:51
  • @Darien nice, we might use strategy pattern. In that case, our policies are executed on Repo? btw, there is often a significant number of similar commands that could be executed with few sqls. Does this means we should use policies for them? (you may elaborate in an answer ;) – lawpert Oct 30 '14 at 20:50
  • Whoever vote this down, should better explain. – lawpert Oct 31 '14 at 6:30
1

In your particular case, as a rule of thumb, methods which operate on a single entity should be defined on the model itself, whilst those methods which operate on the entity collection as a whole should be defined on the service.

Methods such as getLatest, getMostPopular, getOutOfStock, deleteFromPublisher, deleteFromAuthor are all ideal candidates for being defined on the service in your architecture, since such queries would inspect all existing entities.

To contrast, methods such as delete, hide, setStock, setPrice should ideally be defined on the model itself, since you would utilize these on a particular entity which you have in the current context.

Your concern that you might end up with a lot of such methods on the service is subjective. From the perspective of maintenance, there are ways to deal with this should it become unbearable, but it still doesn't change the fact that these should be qualified from the service object itself.

  • Even delete()? – lawpert Oct 31 '14 at 9:20
  • Depends on how the persistence plumbing is designed, but yes, there are some naked designs circulating in the wild which have this implementation. Observe the use of class and instance methods which discriminate operations on the whole collection or a single entity: new Book(data).save() and Book.create(data); in such a design, you would use book.delete() instead of something like Books.delete(book). See this for an example docs.djangoproject.com/en/dev/topics/db/queries/…. – Filip Dupanović Oct 31 '14 at 12:13
  • In case of book.delete(), wouldn't the entity Book contain a reference to the repository? – lawpert Oct 31 '14 at 12:15
  • Yes, exactly! Dynamically typed languages have sophisticated reflective capabilities and statically typed languages can make use of dependency injection and factories to facilitate this reference. Aside from anemic models, Fowler also conceptualized the Active Record pattern and it's implementations are still evolving. This approach twines all those different designs to be exposed on the entity's resulting type, and instances of, for service-like operations. Essentially, your entity is fully aware it is persisted in some data store and part of a collection. – Filip Dupanović Oct 31 '14 at 17:41
  • I would just like to add that having these smart entities lends itself to the resulting design. If you can reuse their behavior and transform these additional objects as intrinsic features of an entity, your entities would literally sit directly on top of the repositories, since the services, their repository client and other delegates are literally inlined and no longer a member of your DDD. This would allow you to fully focus on the business requirements. – Filip Dupanović Oct 31 '14 at 18:07

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.