1

I'm trying to create a Required Field Value Object class that will be reusable across Entities in my Domain Model. I'm still learning the C# syntax (been coding in VB.net forever). And I'm all new to DDD (but have at least read several books).

My goal is to design a Value Object called RequiredField<T> that can accept just about any object (e.g. value type, reference type, or nullable value type (int, string, int?)) which can then be validated before allowing it to become part of an Entity's state. I would use this Value Object any time my entity has a required field (e.g. id, primary key, name, or any other piece of state deemed necessary to have a valid entity). So the Entity will define properties as RequiredField<T> whenever I have a simple piece of data that is required in order to have a valid Entity.

So I've been fiddling around with this class, and I'm getting closer, but it seems like every time I think I've just about got it, I run in to another stumbling block. Here is what I would like the usage to look like, from my Entity class:

public class PersonEntity
{
    public RequiredField<long> ID { get; private set; }
    public RequiredField<string> Name { get; private set; }
    public RequiredField<DateTime> DOB { get; private set; }
    // define other non-required properties ...

    public PersonEntity(PersonDTO dto)
    {
        ID = new RequiredField<long>(dto.ID);
        Name = new RequiredField<string>(dto.Name);
        DOB = new RequiredField<DateTime>(dto.DOB);
        // set other non-required properties ...

    }
}

The corresponding DTO that is used to construct the Entity (created in the repository, or application service from the UI, or from a WebService, etc):

public class PersonDTO
{
    public long? ID { get; set; }
    public string Name { get; set; }
    public DateTime? DOB { get; set; }
}

Note that I really desire the ability to have the DTO be just a data bag (that's basically all a DTO is right?). If I don't allow nullable types here, then I have to do validation somewhere else, and the whole point is to let the Value Object in the Entity do the work (right?).

Finally, here is what I have so far on my RequiredField<T> class. Note that this code doesn't compile.

public class RequiredField<T>
{
    private T _value;
    public T Value
    {
        get { return _value; }
        set
        {
            // handle special case of empty string:
            if (typeof(T) == typeof(string) && string.IsNullOrWhiteSpace((string)value))
            // but (string)value doesn't work: "Can't convert type 'T' to 'string'"
            {
                throw new ArgumentException("A required string must be supplied.");
            }
            else if (value == null)
            {
                throw new ArgumentException("A required field must be supplied.");
            }
            // also need to handle Nullable<T>, but can't figure out how
            else if (Nullable.GetUnderlyingType(typeof(T)) != null)
            // need to check value, not T
            {
                throw new ArgumentException("A required field must be supplied.");
            }
            _value = value;
        }
    }
    public RequiredField(T value)
    {
        Value = value;
    }
    // below is the start of failed attempt to accept a Nullable<T>
    // don't like the fact that I have validation going on here AND in the setter
    public RequiredField(object value)
    {
        if (!value.HasValue)
        {
            throw new ArgumentException("A required field must be supplied.");
        }
        Value = value.Value;
    }
}

So I've gotten myself pretty far into a mess, and I started to question if I'm attempting to do the right thing here. But if I am on a good start, what gets me over the finish line?

svick
  • 236,525
  • 50
  • 385
  • 514
Scuzzlebutt
  • 494
  • 9
  • 18
  • Why do you need a specific case for `Nullable`? Just compare with null: `value == null`. For string use `Convert.ToString(value)` – DavidG Feb 02 '17 at 01:20
  • I can't pass a `Nullable` into the constructor `public RequiredField(T value)`. I get 'cannot convert from 'long?' to 'long' – Scuzzlebutt Feb 02 '17 at 01:27
  • I thought `(string)value` did the same thing as `Convert.ToString(value)`. Apparently it doesn't. That looks like it works. I'll have to go research the difference between the two. Thanks. – Scuzzlebutt Feb 02 '17 at 01:29
  • I would put this kind of validation in the command itself, not in the entity – Constantin Galbenu Feb 02 '17 at 01:37
  • So I have about 80 different Entities, and most of them will be created by data from repository, or web service, or UI, and I'm supposed to distribue entity data validation to all of those cases before I even think about attempting to create the entity? From my understanding, Entities are supposed to validate themselves as a last line of defense. I know that I will be validating fields all over the place already. Trying to minimize it. That has bad code smell to me (no offense). – Scuzzlebutt Feb 02 '17 at 02:11
  • 1
    There are different kind of "validation". I recommend that you read this article: http://verraes.net/2015/02/form-command-model-validation/ – Constantin Galbenu Feb 02 '17 at 08:15
  • Nice article. I agree with (and already understood) pretty much all of it. Are you suggesting that I use VOs (with validation) in my DTOs instead of using primitive types? I can't really do that can I? I need a DTO (property bag) that can be used to create and persist NEW Entities, and I won't know what the RequiredField (PK) is until it has been persisted. I'm at the early stages now, but it seems like I need to do a little more planning here. Used to the old "Transaction Script" where everything was pretty cut and dry (until it grew to a big mess)! – Scuzzlebutt Feb 02 '17 at 17:39
  • To quote Millett in his PPP of DDD book: "Value objects should never be in an invalid state. They themselves are solely responsible for ensuring this requirement. In practice, this means that when you create an instance of a value object, the constructor should throw an exception if the arguments are not in accordance with domain rules". It seems to me that is exactly what I'm trying to do here. – Scuzzlebutt Feb 02 '17 at 17:44

3 Answers3

4

I started to question if I'm attempting to do the right thing here.

Good, you should be questioning that -- the literature recommends that you to go the other way.

I'm trying to create a Required Field Value Object class that will be reusable across Entities in my Domain Model.

That's probably the wrong goal to have.

Evans Chapter 5 describes a number of tactical patterns for expressing the domain model, including the ValueObject pattern. The critical insight in the pattern is that it is important your software describes what the value represents, rather than how it is implemented in memory.

public RequiredField<DateTime> DOB { get; private set; }

So this declaration is trying to tell us that this field is part of the query api for this entity, that the value is required, that in memory the state is a handle to a data structure that supports the DateTime api.

What's missing is that the data is the DateOfBirth.

There are a couple of problems here -- first, RequiredField is not drawn from the ubiquitous language; it's artificial programming vocabulary that means nothing to your domain experts.

Furthermore, it fails to model DateOfBirth correctly (think about what date of birth is -- a local date as measured by a clock in the locale where the person was born). Time arithmetic on a DateOfBirth doesn't work.

What that means, among other things, is that you want to avoid confusing DateOfBirth with other time like things where date arithmetic does work.

So your constructor should look like

public PersonEntity(PersonDTO dto)
{
    ID = new Identifier(dto.EY);
    Name = new Name(dto.EID);
    DOB = new DateOfBirth(dto.DOB);
    // set other non-required properties ...
}

This gives us a natural place to put our data validation (in the constructors of the value types)

Furthermore, you probably want to mark the optional fields, rather than the explicit ones, when you are in the model. Compare C# with the usage of Optional in Java.

Spelling this point another way, RequiredField is an algebraic data type, roughly corresponding to Unit -- you've created a type of types that can only assume one type.

In messaging, you are more likely to want "optional" fields by default, because the flexibility to be forwards/backwards compatible with other implementations is valuable. You want to be able to read messages written by past versions of the model, and write messages that will be read by future versions of the model.

Same idea, different spelling -- the concerns at the boundary differ from those in the model

Effectively, it comes down to this; the state in the model is constrained, but the constraints live in the model itself -- once the state is extracted from the model (once you create the DTO), the constraints are gone. The data is just a byte array; reading the data back in, we re-apply the constraints so that the model doesn't have to constantly keep checking (in other words, the DRY principle shows up here).

the pragmatist in me didn't want to create a zillion different value objects when most of them just need to be required, and have no extra validation or behavior.

Even if there's no validation, and even if there's no "extra" validation, there's still the fact that substituting types for other types is an error, as far as the business is concerned -- we can represent both FamilyName and City as string, but that implies that they are interchangeable, which is not at all the case.

Put another way, nobody sane says int, strings, oh my god strings have encoding, its all too complicated, I'll just model everything as byte[].

See also

That said, the cost of being wrong may not exceed the work of being right. Composing boiler plate code is not fun, you may need to write your value types and primitive to value conversions in a language more suited to the task. Trade offs abound.

So my take-a-way from this is that I should define separate VOs, and have each of those use a RequiredField helper (or perhaps FluentValidation)? This would also make it easy to add differing validations or behaviors to individual VOs.

Common idioms

// constructors
new Value(...)

// factory methods
Value.of(...)
Value.from(...)

// Factories
api.newInstance(...)

// Builder
api.newBuilder()....build()

If that property is simply a description with no role in the domain logic/decisions, can it be a primitive and not a VO?

Note: if the property has no role in the domain logic/decisions, why include it at all?

It can be, yes, but it really shouldn't be. The value types are your corpus for a domain specific language you are using to model the business. Put another way, the domain behavior shouldn't depend at all on how the data is represented in memory.

Consider identities; they are an opaque value type. All you ever do is compare them. There is absolutely no reason that the model should ever need to peek through the veil to know if they have the same underlying data layout.

But even if I had

interface OpaqueValue extends ICanEqual {...}

I would still want

interface Whatzit {
    interface Identity extends OpaqueValue {...}
}

interface Whoozit {
    interface Identity extends OpaqueValue {...}
}

// CompileTimeError
Whatzit.Identifier target = source.getWhatzit().id
VoiceOfUnreason
  • 52,766
  • 5
  • 49
  • 91
  • Thank you for the well thought out explanation. The purist in me felt a little uneasy about the concept of a *RequiredField* as a VO. But the pragmatist in me didn't want to create a zillion different value objects when most of them just need to be required, and have no extra validation or behavior. So my take-a-way from this is that I should define separate VOs, and have each of those use a *RequiredField* helper (or perhaps FluentValidation)? This would also make it easy to add differing validations or behaviors to individual VOs. Makes sense. – Scuzzlebutt Feb 03 '17 at 17:16
  • If you would, could you comment on using primitive types as properties in an Entity? Millet's PPP of DDD book says: "Although it is possible to represent descriptive concepts with primitive types, most DDD practitioners strongly discourage it. Instead, primitives should be wrapped up into cohesive value objects that explicitly represent the concepts they are modelling." For example, a vehicle Entity with the property *NumberOfWheels*. If that property is simply a description with no role in the domain logic/decisions, can it be a primitive and not a VO? – Scuzzlebutt Feb 03 '17 at 17:31
  • Can't tell you how much I appreciate your thorough and helpful answer to my question. I figured out how to solve the validation implementation, but you confirmed my worries about my chosen path of not using VOs correctly. As a sole proprietor, I don't get the benefit of popping into the next cubicle to "talk shop" about theory and design. The articles you linked to were very insightful too. Thanks! – Scuzzlebutt Feb 04 '17 at 00:24
3

I would recommend leveraging existing ways of validating input rather than rolling your own RequiredValue type.

Some options:

  1. Guard clauses in your constructors. You can use a library if you want to help here I.e. liteguard
  2. Attribute based - 'Required' attributes, I.e. Something like DataAnnotations
  3. More complex logic can be encapsulated with something like FluentValidation
tomliversidge
  • 2,339
  • 1
  • 15
  • 15
  • I appreciate the ideas. I'm already learning a bunch of new stuff as I try to "modernize" my design. I was hoping to not have to rely on (i.e. *learn*) even more new stuff (like external libraries). I would prefer to solve as much as possible with my own code (its a good learning exercise anyway). I will of course use the built in DataAnnotations on the webui side. I guess I didn't think my little problem here would be that hard to solve! – Scuzzlebutt Feb 02 '17 at 17:04
  • Its pretty simple to write your own guard clauses if you want to go down that route, you can use generics to make them more re-usable – tomliversidge Feb 02 '17 at 19:37
  • Would you care to enlighten me? I've stated my problem case in the question. Looking for an answer! Thx. – Scuzzlebutt Feb 02 '17 at 19:46
  • 1
    https://github.com/adamralph/liteguard/blob/master/src/LiteGuard/Guard.cs shows the idea - given a type, ensure that some expectations are met. – tomliversidge Feb 02 '17 at 20:56
  • 1
    You dont need to use generics either, for example https://github.com/danielwertheim/Ensure.That/blob/master/src/projects/EnsureThat/EnsureArg.Strings.cs – tomliversidge Feb 02 '17 at 20:58
1

Alright, thanks to some nudges in the right direction, and help from this solution, I came up with my own. It could probably be a little prettier, but it gets the job done (passes all my unit tests so far!).

I ended up having to box the input value. If there is a way to do it without boxing, I'd certainly still be interested in a cleaner solution.

public class RequiredField<T>
{
    private T _value;

    public RequiredField(IConvertible value)
    {
        SetValue(value);
    }

    public T GetValue()
    {
        return _value;
    }

    public void SetValue(IConvertible value)
    {
        Type t = typeof(T);
        Type u = Nullable.GetUnderlyingType(t);

        if (value == null)
        {
            // reference object is null
            throw new ArgumentException("A required field must be supplied.");
        }
        else if (value is string && string.IsNullOrWhiteSpace(Convert.ToString(value)))
        {
            // string is null or empty or whitespace
            throw new ArgumentException("A required field must be supplied.");
        }
        else if (u != null)
        {
            if (value == null)
            {
                // Nullable object is null
                throw new ArgumentException("A required field must be supplied.");
            }
            else
            {
                // Nullable object has value
                _value = (T)Convert.ChangeType(value, u);
            }
        }
        else
        {
            // value object is not null
            _value = (T)Convert.ChangeType(value, t);
        }
    }
}
Community
  • 1
  • 1
Scuzzlebutt
  • 494
  • 9
  • 18
  • @VoiceOfUnreason got the accepted solution, as I was trying to use a VO in the wrong way. But this does still demonstrate a way to get the desired behavior for validation of a required field with various underlying primitive types. – Scuzzlebutt Feb 04 '17 at 00:28
  • You might try checking out the [DDD/CQRS google group](https://groups.google.com/forum/#!forum/dddcqrs) for some DDD arch advice. Be wary that discussions there are often too abstract to be useful, though. – Kasey Speakman Feb 16 '17 at 22:20