How to deal with updating Entity (CRUD) and Domain Events using DDD?

2.2k Views Asked by At

I know that DDD is good with a Task-Based UI, but I'm refactoring a legacy app, where I have Anemic Domain Model (many setters without business logic).

One of the first steps was to make it reach model and add Domain Events. While adding events for creating (TaskCreated in constructor) and removing (TaskRemoved) the model is an easy process, I'm struggling with updating the model.

We have a RESTful API with PUT /tasks/{id} endpoint. Under the hood the framework maps the body of the response to DTO object and then calls setters one by one:

task.setText('new text');
task.setStartDate(newStartDate);
// and so on

I want to listen some event when the task is updated and update it in e.g. Google Calendar. As you can imaging, if I record events in each setter (TextChanged, StartDateChanged) and listen all of them, I will end up with many API calls to the Google API, which is not what I want.

Question is: how should I work with Update operation in the right way? Should I replace all those setters calls with one update(newData) call and dispatch only one domain event there? How to make only one API call to google calendar after the task is updated?

2

There are 2 best solutions below

1
On

I prefer the one-event-per-set way, because the update action sometimes is just an use case, imagine that you will have to, later in the domain, change just one field of an entity because of an external process, you shall have a command representing that use case and not an entire update.

Now the question arises: how do I track down the events that were fired based on a single use case? Simple, use some kind of correlation identifier, that could be the request Id for example.

To achieve that you may use a list that holds the domain events and, when you save your transaction, you dispatch the events and, as they were created within the same logical context, they will have the same correlation Id.

1
On

how should I work with Update operation in the right way?

The usual answer is that the domain events are not part of the object you are modifying, but describe the modifications in a separate data structure.

With an anemic model, I would expect the caller to be responsible for the events. That's probably not the framework if the framework is just auto mapping DTO fields to the task. You want the events to be defined at a point in the code that understands the business context of the edits. In other words, you probably want TaskRescheduled rather than TaskUpdated.

In the first draft, you can just publish the event at the point when you know the save is successful.

More robust is to save the list of events with the task. This gives you better stories around reliable messaging - see Udi Dahan Reliable Messaging Without Distributed Transactions to get a better sense for where this is going.

With a domain model that isn't anemic, you would indeed define the event within the Task update (the event in the data model would still be separate from the state of the task).