3

I often run into this decision making scenario of where to call a Domain (or Application Service) when building my Domain Models. Maybe the confusion is in identifying whether this is a Domain service or an Application service itself. I would love to see what others think. I'll try my best to explain this with a simple scenario, and pose additional examples that I run into.

Imagine an Address Domain Model. It has the following items:

  1. AddressLine1
  2. AddressLine2
  3. City
  4. StateProvince
  5. Country
  6. ZipCode

Now I have a constructor defined like so:

Address(string addressLine1, string addressLine2, string city, string stateProvinceCode, string countryCode, string zipCode)

I need to ensure that the State Province code being passed matches a state province in the Country. If I had a database of cities, I would also like to match the City as well as the ZIP code.

In scenarios like these, how do I best solve this? Here are my options:

  1. I keep the constructor super simple, there should be no reason why someone can't stuff whatever data they want to build the Address Object. I then create a method called Validate() in the Domain model which accepts an IAddressValidator which knows how to validate the data.

The implementation of IAddressValidator can be implementation specific.

  1. Alternatively, I introduce the IAddressValidator as a part of the constructor. The problem with this approach is that now everyone wanting to use the Address domain (no matter for whatever rudimentary reasons) now has to worry about building the IAddressValidator implementation.

  2. Do not have IAddressValidator/Validate in the Domain at all. Assume that the Domain will be populated by an Application Service, say AddressService which does the job of validating all of the data and then populating the address model which can later be persisted to the database. This also means that if someone doesn't call the Address Service to do the validations, they risk saving invalid data in the Address.

Likewise, I have a lot of similar scenarios where I feel like I don't know where the best place to validate incoming data is.

Examples:

  1. An example where a user answers survey questions. Each Question has potential answer options that need to be validated before the answer is added to a survey. Does this validation belong at the domain level i.e. should I do SaveAnswer(Answer answer, IAnswerValidator validator)? Or at Service level using IAnswerValidator to first validate the answer and then simply call SaveAnswer(Answer answer) in the domain assuming that all validation will be done by service layer?

  2. E-Commerce Scenario, when an Item is added to cart and we also need to validate if inventory exists. Should we pass the inventory checker interface to the domain like so: AddItem(CartItem item, IInventoryChecker checker)? Or should we do it at a service level and leave the domain with a simple AddItem(CartItem item) method.

1

There seem to be a confusion between several concepts in your question, that deals on one side with DDD, on the other on DI, and finally on architecture layers.

DDD services

Let's first have a look of the definition of a service in the DDD terminology, according to Eric Ewans in his reference book Domain Driven Design :

SERVICE: An operation offered as an interface that stands alone in the model, with no encapsulated state.

Applying this definition:

  • Option 1 implies that your validator is a method of a domain class. In fact, you could even consider to have an isValid property that is set by the constructor and updated every time a setter is invoked. This seems to me a very logical and flexible approach: after all, an address can be temporarily incorrect or incomplete; it must be valid only at the point in time where you want to geolocalize it or ship a parcel.
  • Option 2 supposes that the validator is independent of the address, as it would be invoked by the constructor. So by definition, it would be a domain service. However, the validator is completely dependent of the address (it needs to access all its components) and if you'd change the address structure (for example introduce a separate street number), you'd need to change all the all the potential validator services.
  • Option 3 is a misunderstanding. The fact that an address is valid or not is definitively a domain issue. And more precisely, it is a country dependent domain issue (e.g. you don't validate UK addresses as you would validate US addresses, and France requires numbers at the beginning of the street whereas Germany and Belgium at the end). Suppose that you share addresses between several applications: it wouldn't make sense to have one kind of validation in one application, and a totally different validation in another application !

Dependency injection

In option 2, you consider to inject the validator. This would make sense if you could imagine several validators in your domain. But why would you have several validators ?

You could imagine having different validators for different countries. But the country code is part of the constructor arguments. So if you'd choose in the application layer the validator based on the country you would in fact perform some domain choices in your application. WHat does this mean ? You would accidentally create a tight coupling between your domain and your application: your domain objects are consistent only if the application did choose the right domain service.

Application layer vs domain layer

The service terminology that you use, seems to reflect the onion architecture, which also makes heavy use of DI.

But be careful about the potential confusion: what several architecture models call the domain service is not necessarily a DDD domain service. It is often a layer that isolates the domain logic from the outside world.

Anyway, regardless of the architecture model, according to my arguments above, the validation should be part of the domain logic.

  • I agree on the Validation being a part of the Address domain. If I'm understanding you right, the application concerns should not be mixed with the domain concerns. Using this Domain Service approach: zankavtaskin.com/2013/11/… would you recommend that I simply pass a StateProvince as an argument to the constructor? This will ensure that the Country that the state belongs to is also passed implicitly with the StateProvince. The domain service would load the state by code using a repository and pass it to the Domain model. Thoughts? – Anup Marwadi Aug 21 '18 at 18:43
  • Yes: a clear separation of concerns is the correct approach. The domain service approach presented in that article is correct and you could use it. You could also get the country via a repository. In my opinion, the StateProvince is however an entity belonging to the Country aggregate, because the StateProvince identifier fully depends on the country cpde. – Christophe Aug 21 '18 at 19:48
  • That is correct. So I was thinking of loading the State Province (and it loading the Country with it). Another alternative (albeit expensive one) is to load the Country and all its State provinces and still pass Country and State Province code. The earlier approach is much better because I can load the state based on CountryCode and StateCode and if that matches, I get a StateProvince with Country back which I pass to the domain model – Anup Marwadi Aug 21 '18 at 21:26

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.