How do you deal with domain model validation that requires touching an infrastructure component?

359 views
Skip to first unread message

Jack Snow

unread,
Apr 28, 2016, 3:33:18 AM4/28/16
to DDD/CQRS
I read that in general the domain model should be as pure as possible and not have to depend on things in the application and infrastructure level.

I have 2 examples:
1. I have a user entity which is an aggregate root. The entity contains an email address value object. There is an invariant that each user's email address must be unique. How do I enforce this invariant when a user is created or changes his email address? Should the validation be in user.UpdateEmailAddress() and the constructor (new User(EmailAddress email))? Wouldn't this require the User entity to have a reference to the UserRepository which has the userRepository.FindUserByEmail() method?

2. I need to deal with credit card payments. To ensure that the credit card numbers do not much my systems, the browser (client) talks directly with the payment gateway and creates a token representing the card. The client then sends the token to the server where it is persisted in the user's wallet. Before storing the token to my database, I need to verify that the token is valid by using the REST api of my payment gateway. Since this means something in my domain model needs to touch the infrastructure, it seems like a big no-no. How should this be modelled?

Cheers!

Ben Kloosterman

unread,
Apr 28, 2016, 8:12:13 AM4/28/16
to ddd...@googlegroups.com
On Thu, Apr 28, 2016 at 5:33 PM, Jack Snow <infec...@gmail.com> wrote:
I read that in general the domain model should be as pure as possible and not have to depend on things in the application and infrastructure level.

I have 2 examples:
1. I have a user entity which is an aggregate root. The entity contains an email address value object. There is an invariant that each user's email address must be unique. How do I enforce this invariant when a user is created or changes his email address? Should the validation be in user.UpdateEmailAddress() and the constructor (new User(EmailAddress email))? Wouldn't this require the User entity to have a reference to the UserRepository which has the userRepository.FindUserByEmail() method?

As User/ Security has almost no business logic its normally better handled with CRUD. The fact your using update field / FIndUserByEmail confirms this  this.  Its good practice IMHO to have CRUD and DDD BCs depending on what is needed. 

There are dozens of threads on different ways of how to handle duplication eg

- Get the Facade to check before creating a command 
- Create a large aggregate/ Service  with all valid information  eg a users aggregate which then creates a user entity ( which is later used by other aggregates such as User) 
- Allow it then revoke it later ,
etc etc

2. I need to deal with credit card payments. To ensure that the credit card numbers do not much my systems, the browser (client) talks directly with the payment gateway and creates a token representing the card. The client then sends the token to the server where it is persisted in the user's wallet. Before storing the token to my database, I need to verify that the token is valid by using the REST api of my payment gateway. Since this means something in my domain model needs to touch the infrastructure, it seems like a big no-no. How should this be modelled?

Again very little / no business logic , id wrap it in a separate service / class outside of DDD  .  Your domain may use this service with your own logic but the transaction/ comms detail  part is nor part of the domain. 

Don't fall into the traps of modelling everything with an Aggregate . or map one Entity to one Aggregate.

Regards,

Ben 

João Bragança

unread,
Apr 28, 2016, 10:17:25 AM4/28/16
to ddd...@googlegroups.com
Think of it another way. Is your user repository part of your domain model? Yes. Does it need to touch the infrastructure? Yes. What do we do here? The domain model has an interface or delegate that it understands. Then you implement it by leveraging your infrastructure. This is no different.

--
You received this message because you are subscribed to the Google Groups "DDD/CQRS" group.
To unsubscribe from this group and stop receiving emails from it, send an email to dddcqrs+u...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.



--

Danil Suits

unread,
Apr 28, 2016, 10:49:16 AM4/28/16
to DDD/CQRS


There is an invariant that each user's email address must be unique. How do I enforce this invariant when a user is created or changes his email address?

You go back in time, and find the mail administrator that assigned a duplicate email address to this user, and you beat him up.  Make sure it's public, you want the word to get out.

It may or may not help  to review whether or not you are the book of record for "email address", and how that impacts the your domain models.



Before storing the token to my database, I need to verify that the token is valid by using the REST api of my payment gateway. Since this means something in my domain model needs to touch the infrastructure, it seems like a big no-no. How should this be modelled?

That sounds to me like a query that takes a token as an argument.  Maybe a "domain service" is encapsulates the query, and the model executes the query by passing the token.  But like Ben, I'm suspicious -- why does the domain model need to validate the token, can't the application do that?
 

 

Aryeh

unread,
Apr 29, 2016, 3:05:20 AM4/29/16
to DDD/CQRS

Hi Jack,

Of course elements in a Problem Domain (PD) can interact with other systems.  How would an elevator move if logic couldn't tell something representing the physical elevator to move?  How would an aircraft system instruct a physical flight surface to change position?  How would a cash-draw open in response to the PD handling a cash payment?

Need to validate or authorize something like in your second example? The traditional way to model this is to create two objects.  One in your Problem Domain abstracting the external system and one outside the PD representing the object that actually interfaces with the external system.  From a code organizational perspective, consider that second object to be part of say "System Interaction" (SI).  That SI object is often one or more objects (a library) supplied by a manufacturer or 3rd party.  But it can just as easily be an external server somewhere with an accessible API etc.

Validating your credit card is a part of your problem domain, and should be reflected as such.  Abstract an external system and make it explicit in your Domain Model.  You now have a place to apply any business rules (constraints) relating to authorization (or validation etc) in your domain.  I know this is so confusing because there is so much misinformation about, especially in regards to which concepts should be in the "Application layer" versus the PD.

One final point, communication between PD and SI objects are typically by sending a message (method call), not by raising an event :)

Best regards,
Aryeh Hoffman

Aryeh

unread,
Apr 29, 2016, 3:22:17 AM4/29/16
to DDD/CQRS
Jack,

One more thing I should have mentioned, is the PD "AuthorisationManager" can be considered an example of a DDD "domain service".

Regards,

Aryeh Hoffman

On Thursday, April 28, 2016 at 10:33:18 AM UTC+3, Jack Snow wrote:

Jack Snow

unread,
May 2, 2016, 8:21:17 AM5/2/16
to DDD/CQRS
Thanks guys, your responses are very helpful :) There's still a lot for me to learn as I explore DDD, but the pieces are starting to fall into place!
Reply all
Reply to author
Forward
0 new messages