Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Domain Objects and Services

Tags:

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?

like image 560
Todd Smith Avatar asked Jan 12 '09 21:01

Todd Smith


People also ask

What are the domain objects?

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).

What are domain services?

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.

What is a service domain example?

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.

What is a service in domain driven design?

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.


1 Answers

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:

  • The logic should be domain logic, i.e. nothing like image.load() or image.save()
  • The logic shouldn't give the object more than "one reason" to change in the domain. This is a re-statement of the SRP.
  • The logic shouldn't be forced into the object. In other words, if you end up doing something like trying to calculate the sum of some property in a list of domain objects without using a getter, think twice.

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.

  • For simple objects, like the UserImage, significant domain logic that can fit in the object itself might be scarce because it isn't, as far as I can tell, an Aggregate. Aggregates, I think, present more of an opportunity to house domain logic. The Account example is likely an Aggregate.
like image 68
moffdub Avatar answered Sep 20 '22 19:09

moffdub