17

As DDD practitioner advise, business rule's validations must be implemented inside domain objects (Entities, Value Objects and Domain Services) and follow their own context also somewhere i've 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.

Now my question is this:

If we had a Value Object for credit card number, should we still 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?

When an incorrect debit card's number or even an email address has a potential to break business rules, what then?

For more clarity please notice this Value Object which represent an Debit Card Number:

    public class DebitCardNumber : ValueObject
{
    public string Number { get;private set; }

    public DebitCardNumber (string number)
    {
        Validation(number);

        this.Number = number;
    }

    private void Validation(string number)
    {
        if (String.IsNullOrWhiteSpace(number))
        {
            throw new CardNumberCanNotBeEmptyException();
        }

        if (number.Length != 16)
        {
            throw new CardNumberLengthMustBeSixteenDigitException();
        }

        int sum = 0;
        for (int i = 1; i <= 16; i++)
        {
            if (!char.IsDigit(number[i - 1]))
            {
                throw new ValueContainsSomeNonDigitCharacterException();
            }

            int m = (i % 2 == 0 ? 1 : 2);
            int a = (int.Parse(number[i - 1].ToString()) * m);

            while (a > 9)
            {
                a -= 9;
            }

            sum += a;
        }

        if ((sum % 10) > 0)
        {
            throw new ValueIsNotCorrectAsACardNumberException() 
                { Message = "Perhaps some digits has been entered in wrong order or they are incorrect." };

        }
    }
}

According to this code there is a Validation method that carry out an algorithm to find out either is it Card Number's format correct or not? do you think is it right place for this type of validations?

Masoud Sedghi
  • 495
  • 1
  • 6
  • 19
  • The value object should not be able to construct if it is not valid. You should put all those validation rules inside constructor, to guard against creating invalid object. – nemke Mar 21 '21 at 16:05
  • Why is class DebitCardNumber ,but constructor Credit card number? – cikatomo Apr 24 '23 at 16:44
  • @cikatomo tnx for your attention,I edited the code sampe after about 7 years :) – Masoud Sedghi May 06 '23 at 15:32

4 Answers4

18

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).

VoiceOfUnreason
  • 52,766
  • 5
  • 49
  • 91
  • I am also confused.because I've being read a official book which had recommended that technical validation (data type,length,missing input,format) should carry out some where out of Entities and it had introduced Application Service for this goal. I think it's good for Transaction Script. about your caution: yes when a debit card number is invalid some rules of business will be broken.for example when a back office user is wanted to charge a debit card if the debit card number is invalid obviously this request could not be met.so I think it's better to avoid this problem at initial point. – Masoud Sedghi Aug 30 '16 at 20:16
  • 1
    I guess that you could version value objects by keeping their old constructor around, but mark it as deprecated and perhaps even make it private (if you reconstruct value objects through reflection). – plalx Sep 01 '16 at 02:37
3

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.

tomliversidge
  • 2,339
  • 1
  • 15
  • 15
3

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.

Erik Lott
  • 697
  • 1
  • 9
  • 17
  • I'm sure business cares about a card number being in a valid format because at some point they'll want to use the card for transactions. If the card is invalid then it's worthless to the business. – Creative Nov 08 '22 at 13:02
  • @Creative I agree, the business will care if the card is valid. The question is where to implement that validation logic. You could validate the card format in a Value Object constructor, but I would argue that unless the subdomain that you are modelling specifically solves the problem of billing, payments, invoices, etc, the complications of validating the format of the multitude of cards that could be used for payments in your system is best left to your payment provider (Stripe, PayPal, etc). Make a quick service call instead (e.g. stripe.isCardValid(XXX)) to check if the card is valid. – Erik Lott Nov 08 '22 at 15:43
2

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.

gurghet
  • 7,591
  • 4
  • 36
  • 63
  • so if I take this approach then I should put many validations like this in my domain objects.for example: an incorrect Email address, a too many long Name and Family,a null input value and so on.the main question here how I can distinguish between domain object validations and technical ones. each validation I put finger on it could blow up the logic if it doesn't pass it,therefore I keep that validation in domain object but I guess it doesn't completely right.which type of validations mustn't be involved in domain? – Masoud Sedghi Aug 30 '16 at 14:31
  • 1
    The seams between objects or outside of objects are to be validated at a lower or higher level. For example you wouldn't validate the card number against a database, the higher levels should do that. Similarly the string encoding should be validated somewhere else. The Luhn algorithm, that is for sure to check *inside*. In your case, you could validate that the string is numeric at application level. – gurghet Aug 30 '16 at 14:48
  • 4
    Yes you should put this validation inside your domain. All of the things you have mentioned are domain concerns. For example, something being 'null' - if your domain requires that something exists, it is a domain rule, so null is not allowed – tomliversidge Aug 30 '16 at 15:09
  • gurghet and tomliversidge thanks for your helpful comments.Could you please say some validations that "should not" be put inside the domain? it's kind of you if explain with some examples – Masoud Sedghi Aug 30 '16 at 15:47