Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

doing entity delete in DDD

I am learning DDD and have this basic question:

It seems with factories, rich domain models, repositories the Create,Read,Update (of CRUD) are taken care of, but what about delete? There could be some business logic around delete of an entity where do you handle that? RepositoryImpl(which belongs to the infrastructure) layer should not bother itself checking those invariants, its job is to remove the given entity from the underlying datastore. This seems to be the diametric opposite of the intent for Factories, but DDD doesn't have something like "kill" factories for delete.

Say there is an Order entity that users can delete, but not until it is in "Fulfilled" state, so a client requesting a delete repo.delete(ent) should get an Exception. Similarly there could be scenarios in which when a client requests a delete it results in an update(may be a status change or setting soft-delete flag).

Where should one handle such scenarios entity.delete() (does it make sense?) or in a Application or domain service called delete. What I am worried is as long as Repository interface has that method called delete, any client can bypass the service methods and call repo methods directly.

Just to add a context, how I would structure my layers is through Java package, and use package visibility as a tool to forbid corrupting interactions amongst layers.

like image 790
redzedi Avatar asked Aug 01 '12 09:08

redzedi


1 Answers

As far as I know there are no specific guidelines for Delete in DDD ('Delete' is a very generic and data-oriented term). It is referred to as 'End of life' and it is a responsibility of the Repository. Most of the time, end of life is not simple and is associated with some business rules, maybe state changes etc. Very often domain objects don't get deleted at all, they just transition to 'Archived' state. I highly recommend reading this article by Udi Dahan.

In order to enforce invariants associated with object's end of life you can structure your code like this:

class Order{
  ...
  bool CanBeArchived(){
    ...
  }
  ...
}

interface OrderArchiver {
  // throws InvalidOperationException if order can not be archived
  void Archive(Order order);
}

class NHibernateOrderArchiver implements OrderArchiver {      
  void Archive(Order order){
    if(!order.CanBeArchived()){
      throw new InvalidOperationException("Order can not be archived.");
    }
    ...
  }
}

Method 'CanBeArchived' can also be a part of 'OrderArchiver' interface if the implementation needs access to other domain objects that are associated with the Order.

like image 150
Dmitry Avatar answered Nov 11 '22 23:11

Dmitry