Using External Services in Domain Driven Design

domain-driven-design

I practicing DDD concepts on smaller applications and I use to have the same problem when I have to rely on data coming from outside the domain.

In a previous project, when I wrote an appointment scheduler the appointment could not be cancelled after due date 5 am. So cancelling appointments was dependent on the actual time, which we can call an external dependency. As far as I remember I did something like TimeSercice.canBeCancelled(appointment.getDate()), to cover that 5 am rule, but I am not sure if that was the proper solution. It just seemed important enough to include this rule into the domain, especially because it was part of the user stories. Maybe I was wrong.

Now I face something similar. I write an application, which downloads data from an external service every 30 mins. It is something like downloading probabilities for a GPS grid and if the probability by the user's GPS coord reaches a threshold, then it sends a notification to the user, that something is happening. For now I write it as a native mobile application, but I might move most of the code into a webservice later to make it more reliable and reduce the data traffic. What I thought of is doing something like ProbabilityService.probabilityForPosition(user.getPosition()) to get the probability for the user's position. So that would hide the HTTP calls, parsing the data, etc.

I define the interfaces of these services inside the domain, but the implementation is not part of the domain. I use to inject these kind of dependencies. As far as I remember I injected it by the appointment scheduler from the repositories into the domain objects. Is this a valid approach or DDD follows a different logic if it comes to external dependencies? If so, then why?

Best Answer

Is this a valid approach or DDD follows a different logic if it comes to external dependencies? If so, then why?

Is it valid? yes, in the sense that you will find a number of treatments that seem to do it that way.

But you get something closer to the spirit of "isolated domain layer" if you delegate the retrieval of data from remote processes to the application, and pass that data to the domain model when available.

Which is to say, the primary mechanism for passing new information to the domain model should be command arguments.

In a previous project, when I wrote an appointment scheduler the appointment could not be cancelled after due date 5 am. So cancelling appointments was dependent on the actual time, which we can call an external dependency

For a case like this, our application logic would have two dependencies - one would be the "clock", and the other would be the domain model.

model = repository.get(id)
time = clock.now()
model.onTick(time)

What I thought of is doing something like ProbabilityService.probabilityForPosition(user.getPosition()) to get the probability for the user's position. So that would hide the HTTP calls, parsing the data, etc.

Assuming that user is part of your domain model, the alternate approach would look like:

pos = user.getPosition()
probability = ProbabilityService.probabilityForPosition(pos)
user.updateProbability(probability)

Again, the application is doing the orchestration between our remote data collection capabilities and the domain model calculations.

If you watch Cory Benfield discussion how to design protocol libraries, you'll see this idea within it.