Reputation: 28560
I'm being exposed to DDD for the first time here, mostly, it seems like good stuff but there are some things that are bothering me.
The main one at present is the idea that an object validates itself.
Previously, I would have written a service method similar to this:
public class MyService
{
private IValidator _validator;
private IDomainMapper _domainMapper;
private IThingThatDoesSomething _thingThatDoesSomething;
private IResponseMapper _responseMapper;
public MyService(IValidator validator, IDomainMapper domainMapper, IResponseMapper responseMapper)
{
_validator = validator;
_domainMapper = domainMapper;
_responseMapper = responseMapper;
}
public ResponseDTO DoSomething(RequestDto requestDto)
{
if (_validator.IsValid(requestDto))
{
var domainObject = _domainMapper.Map(requestDto);
var domainResponse = _thingThatDoesSomething.DoSomething(domainObject);
return _responseMapper.Map(domainResponse);
}
else
{
return new ResponseDTO { Valid = false, Errors = /* some error information */ };
}
}
}
However, thy colleagues who have spent more time that me studying DDD prefer the validation and mapping functionality to sit on the domain object. So the DTO look like:
public class RequestDto
{
public string Something {get; set; }
public DomainObject Map()
{
return new DomainObject { something = this.Something };
}
public bool IsValid()
{
return this.Something == "something valid";
}
}
This feel really wrong. Firstly, the object now has multiple responsibilities and secondly, from a domain driven perspective, it seems wrong as I wouldn't expect a letter to arrive at my desk which declares itself to be valid or not or know how to convert itself into something else.
Could someone explain why this is good in DDD?
Upvotes: 2
Views: 2651
Reputation: 1564
First of all i think your original application service code looks better without applying your colleagues suggestions and this is not DDD related at all. Bare in mind that basic coding principles apply always, whether you're using DDD or writing a n-tier CRUD application. Specifically for your original code i mean:
On the other hand there are a few things which can be done better in terms of DDD:
Your mapper apparently can map in both ways (from domain object to data object and the other way around). In DDD domain objects are being created/materialised in a factory (no specific factory implementation is enforced) or/and in a repository. The important fact is that the domain object creation is the responsibility of domain itself, not the application service (as in your code).
You are validating the data object with your validator but i'm not sure you're doing the same input validation in your domain. In DDD many people take up an approach which can be summarized in a sentence: "Never let your domain get into an invalid state". I share that approach. In my projects i tend to have a separate validator for an entity if the validation logic is complex. This validator is used by the domain entity itself to validate the input parameters. For simple validation (eg. null and empty string checking) i leave it inside the domain object. As for your data object validation, most people (me included) tend to do it as "near" to the user interface as possible to get a better user experience (eg. faster response with validation errors).
One more thing worth mentioning is that, judging by your last code snippet, it think that you might've misunderstood your colleagues a bit at some point. Your RequestDTO
class is not a domain object so even after getting some suggestions from your colleagues you shouldn't place the validation nor the mapping logic inside it. DTO is a data holder, nothing more.
TL;DR version
Upvotes: 3