This post is the fourth in a series about Poka-yoke Design - also known as encapsulation.

Recently I saw this apparently enthusiastic tweet reporting from some Microsoft technology event:

[Required] attribute in code automatically creates a non-nullable entry in DB and validation in the webpage - nice […]

I imagine that it must look something like this:

public class Smell
{
    [Required]
    public int Id { get; set; }
}

Every time I see something like this I die a little inside. If you already read my previous posts it should by now be painfully clear why this breaks encapsulation. Despite the [Required] attribute there's no guarantee that the Id property will ever be assigned a value. The attribute is just a piece of garbage making a claim it can't back up.

Code like that is not fail-safe.

I understand that the attribute mentioned in the above tweet is intended to signal to some tool (probably EF) that the property must be mapped to a database schema as non-nullable, but it's still redundant. Attributes are not the correct way to make a statement about invariants.

Improved Design #

The [Required] attribute is redundant because there's a much better way to state that a piece of data is required. This has been possible since .NET 1.0. Here's the Poka-yoke version of that same statement:

public class Fragrance
{
    private readonly int id;
 
    public Fragrance(int id)
    {
        this.id = id;
    }
 
    public int Id
    {
        get { return this.id; }
    }
}

This simple structural design ensures that the ID truly is required (and if the ID can only be positive a Guard Clause can be added). An instance of Fragrance can only be created with an ID. Since this is a structural construction, the compiler can enforce the requirement, giving us rapid feedback.

I do realize that the [Required] attribute mentioned above is intended to address the challenge of mapping objects to relational data and rendering, but instead of closing the impedance mismatch gap, it widens it. Instead of introducing yet another redundant attribute the team should have made their tool understand simple idioms for encapsulation like the one above.

This isn't at all hard to do. As an example, DI Containers thrive on structural information encoded into constructors (this is called Auto-wiring). The team behind the [Required] attribute could have done that as well. The [Required] attribute is a primitive and toxic hack.

This is the major reason I never expect to use EF. It forces developers to break encapsulation, which is a principle upon which I refuse to compromise.


Comments

Seems like overkill if all you have is a piece of data that you want to display on a web page. Are you against using Entity Framework to fill Data Transfer Objects to be displayed?
2011-05-27 13:59 UTC
Agreed, I'd only use [Required] for validation on a view model
2011-05-27 14:35 UTC
You misstate the intended purpose of the attribute, because you cite a tweet instead of the documentation.

It is true that most code-to-schema-mapping-tools, including EF code-first, Fluent NHibernate, and others, will infer non-nullability from [Required] if it happens to be present on a type which is actually nullable. Why shouldn't they? I realize it's cool for the hip kids to flame EF at every opportunity, but good grief, it didn't cause the tornadoes in Memphis, and it didn't create (nor does it "require") [Required]...

The documentation makes the intended purpose of the attribute clear:

"The RequiredAttribute attribute specifies that when a field on a form is validated, the field must contain a value. A validation exception is raised if the property is null, contains an empty string (""), or contains only white-space characters."

Your "imagined" code example is indeed redundant even in the case where someone is trying to create a non-nullable DB field instead of using the attribute for its intended purpose, because integer properties, being value types, are always mapped to non-nullable fields, with or without [Required]. One must use "int?" to get a nullable DB field; [Required] has no effect on "int" at all. (Indeed, the MVC framework, e.g., treats [Required] and value types exactly the same.)

Now, let's consider the actual purpose of required, per the documentation, and see if it's redundant. Consider a view model with two "required" strings. The business requirement is that if either one or both of them do not contain a non-empty string, the web page should highlight the editors in red and display an appropriate message to the user. One could write a parameterized constructor and throw if they're not present, per your example, but you only get one chance to throw an exception, so you would have to handle three separate cases: The first field missing, the second field missing, or both fields missing. Better to use a validation framework which handles all of these cases for you -- which is exactly what [Required] is intended for.

I would argue that such a parameterized constructor with one or more throws is the wrong design in this scenario, because view models must be able to cope with the task of re-displaying invalid data entered by the user so that the user can correct her mistakes. In contrast to a business object, it must be able to hold and report on invalid states.
2011-05-27 15:19 UTC
Ben, if all you have "is a piece of data that you want to display on a web page" you're most likely in the CRUD application scenario. There are cases where this is indeed the correct solution to a business problem. It's perfectly fine, but it has nothing to do with object-orientation.

This whole series of posts about Poka-yoke Design are about encapsulation, which is an object-oriented principle. And yes: when it comes to OOD I'd never use EF (or any other ORM) if it requires me to break encapsulation.
2011-05-28 21:29 UTC
Craig, I agree that when it comes to user input validation, using an attribute on one or more properties with very loose invariants is the best solution. In general, when at the boundary of an application, it's always best to assume that input can be invalid in all sorts of ways. This is true for UI input as well as automated input (XML, CSV, JSON, etc.). Thus, any 'object' modeling an application boundary data structure is essentially not encapsulated.

However, it would be a grave mistake if we let UI concerns drive the design of our domain models. Thus, as soon as we know that we have a case of valid input data on our hands, we must translate it to a proper encapsulated object. From that point on (including db schema design) an attribute would certainly be redundant.

BTW, don't read to much into the tweet. Perhaps I chose the wrong example, and it was never my intention to thunder particularly at EF. So far, all I've heard about NHibernate indicates to me that it has similar issues with regards to encapsulation.
2011-05-28 21:42 UTC
I like what you said in above: "Thus, any 'object' modeling an application boundary data structure is essentially not encapsulated." That's an insight that many people miss.

My personal take on this is that data service interfaces are boundary structures themselves, and should be BOs in the same way that view models shouldn't be BOs, either.
2011-05-31 14:56 UTC
When you say 'BO', do you mean 'Boundary Object' or 'Business Object'? It seems to me that you might use both abbreviations in the same sentence... or I'm totally missing something :)
2011-05-31 18:19 UTC
Sorry, I meant business object, and "should" should have been "shouldn't." Not the clearest sentence I ever wrote!
2011-05-31 20:39 UTC
Gotcha! Agreed :)
2011-05-31 20:40 UTC


Wish to comment?

You can add a comment to this post by sending me a pull request. Alternatively, you can discuss this post on Twitter or somewhere else with a permalink. Ping me with the link, and I may respond.

Published

Friday, 27 May 2011 13:21:06 UTC

Tags



"Our team wholeheartedly endorses Mark. His expert service provides tremendous value."
Hire me!
Published: Friday, 27 May 2011 13:21:06 UTC