A problem that we experienced recently was that of dealing with and wrapping lookup tables. By definition, a domain model is supposed to be isolated from the outside world. It shouldn't have any concept of data access or persistence. Because a domain model is isolated and we don't want to inject services or objects into our domain object, how do we go about querying lookup tables?
In our particular domain, we have about a dozen industry-mandated lookup tables that we query 30+ times in various ways. Each lookup depends upon the previous one. Normally a transaction script processing pattern would be ideal for this type of operation, but we have significant and complex logic surrounding each lookup and this logic varies depending upon shifting industry standards. Complex logic that changes often…sounds like a great place for a domain model. Except for the lookup tables.
The strongest possibility was to wrap the lookup tables in a domain service and use double dispatch by submitting the appropriate service to the aggregate. Ever since Udi's SOA course, I've lost my taste for double dispatch on domain objects. Where does that leave us?
We were stuck until we re-read Udi's Domain Events Salvation post. The answer was to raise a domain event indicating that a certain step had been completed. Then, another object, perhaps a domain service, would subscribe to that event and perform the appropriate lookup. Once the lookup was complete it would raise another event (LookupPerformedEvent) which would contain the results of the lookup. Finally, another event handler would subscribe the LookupPerformedEvent and route that information back into the domain.
The beauty of this mechanism is that the domain is blissfully unaware of the external service being provided by the lookup. It simply knows that it gets the data that it needs and continues operating. Furthermore, the domain has no concept of physical distribution or location of the lookup operations. The lookup tables and lookups could be performed in process or they could be performed on a remote system where the various LookupPerformedEvent messages would then be routed back to the domain through the appropriate message handler.