In this question someone replies "You never let the domain object implementations call services by themselves!". Is this statement a hard fast rule of DDD or does it depend on your own application and architecture?
Contrived example:
As an example lets suppose we have a UserImage
object in our model that gets populated from an uploaded image by a user. And then lets suppose that we can submit this image to a 3rd party service that can identify thumb prints and return a Guid
if a match is found.
public IThumbPrintService { Guid FindMatch(Bitmap image); } public class UserImage { public Bitmap Image {get; set;} public Guid ThumbPrintId {get; set;} public bool FindThumbPrintMatch() { // Would you call the service from here? ThumbPrintId = _thumbPrintService.FindMatch(this.Image); return ! ThumbPrintId.CompareTo(Guid.Empty); } } public class RoboCopUserImageService : IUserImageService { // Or move the call to a service method // since it depends on calling a separate service interface public bool FindThumbPrintMatch(UserImage userImage) { userImage.ThumbPrintId = _thumbPrintService.FindMatch(userImage.Image); return !userImage.ThumbPrintId.CompareTo(Guid.Empty); } }
What is avoided or gained by not letting domain objects call services themselves?
EDIT: Are there any good online articles that discuss this specific topic?
A domain object is an entity in the domain layer of your application, eg. an Address class. "Model" means the same thing - an entity in the "Domain Model". A POCO (plain old CLR object) is an object that has no behaviour (methods) defined, and only contains data (properties).
Service Domains are logical groupings of service-level aspects that enable the system to measure provisioning in different categories. Examples of Service Domains include Availability, Backup, and Help Desk.
A Service in Domain Driven Design is simply a stateless object that performs an action. For example, an AuthenticationService would have the sole responsibility for authenticating users into your application. An important characteristic of a Service is that it should not have state.
Domain Services (or just Services in DDD) is used to perform domain operations and business rules. In his DDD book, Eric Evans describes a good Service in three characteristics: The operation relates to a domain concept that is not a natural part of an Entity or Value Object.
This is the Spreadsheet Conundrum: does the phone dial the phone number, or does the phone number dial itself on the phone?
You might find Double Dispatch to be interesting reading, though overkill in your situation, I reckon.
The Single Responsibility Principle is often at odds with the OO tenet of Tell, Don't Ask. My feeling on the subject has oscillated, and I have settled on the following conditions when logic should go into a domain object:
In your situation, I'd opt against putting the call to the service inside the entity object, mainly because the service doesn't seem like it is related to your domain, but more related to persistence. Domain objects should be coupled to domain concepts, and I don't think the service you gave qualifies.
An example where I think calling a service in an entity might be acceptable would be if your application used a third-party workflow server to manage parts of its state. Essentially, this is the State Pattern with the states defined at run-time.
I think it is acceptable to have domainObject.moveToNextState() (assuming this code "makes sense" in your ubiquitous language) call the service that talks to your server because the workflow server manages a part of the domain model.
I'll add that DDD is very interested with following the language of the domain. Do you hear domain experts saying "A user image finds if its thumb print matches those in the XYZ vendor service"? Or do they say "The XYZ vendor service, given a thumb print, indicates whether that thumb print exists"? Go with the one that makes the most sense in your domain.
Some more thoughts (I've thought about this issue a lot because it is central to design):
In the Evans DDD book, an Account entity has methods like credit(Amount), debit(Amount), transferTo(Account, Amount) and accrue(), but a FundsTransferService has a transfer(Account, Account, Amount) method. The transferTo method doesn't call any service, but merely handles the logic that involves Accounts, like crediting and debiting the right amounts.
The FundsTransferService, in addition to co-ordination, has its own rules to check, rules that don't fit into Accounts. The exact amount to credit or debit might involve outside parties. This makes it awkward for transferTo to call the service.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With