Question

Supposed I have a CQRS-based system and my domain needs some data from an external web service to make its decisions. How do I model this correctly?

I can think of two options:

  1. The command handler runs the domain logic and the domain itself calls out to the web service. Once it gets a response, it attaches the appropriate events to the current aggregate and stores them. The domain basically "waits" for the web service to return.

  2. The command handler runs the domain logic and the domain immediately emits a domain-internal more data needed event. A process manager reacts on this, talks to the web service, reacts on the result, and creates another command on the former aggregate, basically something such as continue.

Which approach is "better", or are both wrong, and I should follow a completely separate way? Basically, I'm fine with option 1, because I think this is basically nothing but a long-running computation inside the domain, but somehow the idea of "waiting" irritates me.

What should I do?

Was it helpful?

Solution

I tend to think of my domain as I do about a physical calculator. It takes input and produces output. That output can be either stored or emitted as events. So in goes data, some behaviour takes place, and out comes data. So very much focused on behaviour.

Your option (1) scenario has resulted in a couple of DDD discussions around injecting services or repositories (or, I guess, an anti-corruption layer) into entities. The general concensus is that it should be avoided and one should opt for, say, double-dispatch. The point is that the domain then needs more information and it either needs to be passed in initially or it needs to be fetched. In my calculator analogy fetching more data is like the calculator prompting you for more input.

If you go with option (1) then whatever is calling the domain needs to handle any web-call failure in order to retry.

If you go with option (2) where you use something like a service bus and, possibly, a process engine of sorts (say saga or workflow) it is quite likely that the service bus handler or the process engine is going to be handling the failures and retries.

I don't think one solution is necessarily 'better' than the other but rather 'different'. I'd go with whatever you feel comfortable with and if you have infrastructure dealing with the failure/retry in some way already then I'd go with the option that is most easily supported by that infrastructure.

Hope that helps :)

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top