Should Value Objects Contain Technical Validation For Input Parameters?

I don't consider your example to be a technical validation rule - I think it is a domain rule of a debit card - if, in the domain of banking, a debit card number must follow a certain pattern, then this is a domain rule that needs to be enforced.

so I think your solution is correct.


if we had a Value Object for credit card number and so on,still we should keep technical validation out of our Value Object? in other words the "Self Validated" term is not involved with technical validations when we deal with Value Objects?

Correct. The domain (entities, domain services, vos, etc) should be modelled such that they enforce business rules, not technical concerns. Your domain may need to distinguish between DebitCards and CreditCards, but I doubt the business cares about the format of the card numbers themselves. The format & correctness of the card number is important for infrastructure purposes, so the formatting rules can be enforce in that layer.


In my opinion your approach is right most cases.

If the number is not valid it's not really a debit card number.

Let's say you have a debit card number that does not validate. Either you have a boolean valid set to false, or your code is lying to you: it's not a debit card number.

If you still want to store the number, maybe for security or UX purposes, you should do that in a different object, maybe inside an Entered Form value object.


as DDD practitioner advise, business rule's validations must be implemented inside domain objects (Entities,Value Objects and Domain Services)

Yes.

also somewhere I'd read that we should put technical validations (such as check length,correct input formats,correct data type,...) out of domain model and somewhere like application layer to keep domain object clear.

A little bit confused here; the main point is that the entities shouldn't need to be worrying about a bunch of input validation, that isn't their job (separation of responsibilities). So instead of passing raw data (strings, primitives) to the entities in our model, we first use the primitives to construct value types that the entity will recognize, and then pass those entities in.

The rules for which primitives can be used to create a well formed value type are properly implemented within the value type itself (constructor) or in a dedicated factory provided for that purpose). The application component has the responsibility to create the value type from the message/DTO it has received before passing that value to the model.

So in your example, the DebitCard validation logic looks like it is in the right place.

A caution - your model evolves over time; when the model changes, you'll still need to be able to read the data written by the earlier version of your model. Adding validation rules that treat your current data as invalid can get messy - so you want to make sure that the validation rules have business motivation. Are you saving money/cutting costs by ensuring that a debit card number has a valid checksum?

(Example: suppose a customer submits a purchase order with an invalid card number. Does the business want to reject that order, or accept that order but defer acting on it until a valid form of payment is provided? If it's the latter choice, you want to make sure that your validation logic doesn't get in the way of accepting the order).