0

I'm studying DDD at the same time that I'm reading some Khalil Stemmler posts and I'm a little confused about who should initialize the VO: the entity it is related to or the useCase that uses that entity. A simple example:

Let's assume that we are developing an internal purchase system for a company that has suppliers in several countries. So the entity Supplier may have properties like name: string, country: Country and taxId: ???. The taxId property has complicated business rules because when a Supplier is from USA the validation rules from TaxId follows the TIN rules, but if the Supplier is from Brazil the taxId validation rules follow the CNPJ rules. Because of this, it is necessary to have a Value Object for TaxId (which probably depends on Country to be instantiated) that deals with these complicated rules, right?

Then follows the central point of my doubt: When instantiating my entity Supplier (in a useCase for example) I must pass as a parameter to the factory method a taxId: string (raw format) and the factory instantiates the Value Object TaxID (ie, if the TaxId is wrongly formatted I can't instantiate my Supplier entity and I get a error message) or should I instantiate the TaxId VO before and in case of success I pass taxId: TaxId as the factory parameter?

1 Answer 1

1

A Supplier factory that that calls a TaxId VO factory is OK. Similarly a Supplier factory that takes a TaxId VO as parameter is also OK. However, avoid having the TaxId validation in the Supplier factory.

Depending on your use cases, you might need to be able to create a TaxId VO without the Supplier entity. If you have such use case, then a Supplier factory that takes an existing TaxId VO would be convenient.

By the way, you should not have an invalid TaxId VO. Yet, the validity of the TaxId VO depends on a Country. Thus, I'd include Country in the TaxId VO (you would be passing the Country to the TaxId factory anyway).

5
  • I don't know if I understood what you meant in the last paragraph. How can I not have an invalid TaxId? If my supplier is from Brazil and TaxId is not a strictly numeric 14-character string then this value is invalid. Mar 11, 2021 at 18:13
  • 1
    @TâmerCuba then the validation fails and you don't make the object. Edit: you are meant to put the data in terms that make sense for your system, and you are meant to take advantage of the type system. In that order of ideas, it makes sense to never create an invalid TaxId VO. If you do, then you need to call a method to check its validity in every place you need to use it. If you don't, then the type is enough to know it is valid.
    – Theraot
    Mar 11, 2021 at 18:31
  • 2
    @TâmerCuba Another way to say the same thing is: the idea is to make invalid tax id values unrepresentable within the core domain layer (or as close to unrepresentable as the language allows for). In other words, it's the best if you can arrange things so that if some code was able to create a TaxId instance, then you can assume it's valid. If, say, a TaxId constructor throws an exception, it should be an exceptional circumstance - in this case, a bug in your code. Now, outside of core domain, within the use cases (application logic), this is not necessarily the best strategy. 1/2 Mar 11, 2021 at 19:35
  • 2
    E.g. if the use case involves users entering tax id-s manually, an invalid tax id is not exceptional. It's a common scenario, and a part of the use case is to assist users with early feedback. So in the use case, you might work with a different representation of the tax id, and only convert it to the TaxId type once the user is ready to commit. You might want to share some of the tax id validation logic between the two, but differ in how strongly they respond to violation, so you might introduce a TaxIdStringValidator service object as part of the core domain that works on strings. 2/2 Mar 11, 2021 at 19:35
  • I like to add the factory code in my Value Objects (factory method pattern), in C# it would be something like public static TaxId ForCountry(Country country, string value)
    – Rik D
    Mar 12, 2021 at 10:44

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.