I've been struggling to figure out a clean way to validate things when objects have complex relationships and the validation requires expensive operations (e.g., making DB queries or other RPCs).
Looking around, I couldn't quite find something that answers this question, so here goes. I've read a bit about domain driven design, domain models, service layers, data mappers, transaction scripts, and anemic vs rich domain models; there's a lot and it's overwhelming with the various opinions.
As an example, let's say we have an Document
object, and it has a list of usernames, but you're only allowed to have usernames for active users. You check if a user is active by calling to an external UserService
. This example can easily grow as you add e.g., attachments, sharing settings, etc, that can only be used with a document under certain conditions and also have their own internal invariants/validation, or require more calls to the database or other external services.
But, just where does/should that validation take place?
- At the level where user input is collected? Leaving the chance for other input points or more internal code to ignore this rule (or more likely, copy/paste slightly different version of it around)?
- On the
Document
object itself? Which results in a strange binding between theDocument
object and the heavy-weight dependency (e.g., as a constructor arg, or a required arg to someisValid
function) - Way down in a persistence layer, so it's always enforced, but muddling persistence with business logic?
- In some middle layer? Still leaving the chance for more internal code to go directly to the persistence layer and skip the rule?
As complexity grows, -- let's say saving a Document
now has a feature where it'll automatically create an Attachment
(which can be created independently and also have their own internal invariants/validation) -- how do you structure/design/architect the application to avoid the sort of problems/short-comings as mentioned above as things grow and change?
-
What happens when users are were linked to documents and then deactivated?plalx– plalx2017年02月05日 04:19:37 +00:00Commented Feb 5, 2017 at 4:19
1 Answer 1
Validation can be put in many places depending on the type of validations. Common places are the UI for fast responses/great ux, on the command itself, on the command handler and on the Aggregate. In the specific case of the Document with usernames and the external service I whould put the validations on the command handler. After that validation passes then the Document Aggregate would enforce the consistency on other business rules that refer to the root entity and its sub-entities.
-
I strongly agree with this. Each layer has its own validation: domain validation its about logic & business: it should be the most complex one. You could add some validation at entity level: ie email has to have specific format (think of entity invariants)user237329– user2373292017年09月22日 11:05:58 +00:00Commented Sep 22, 2017 at 11:05