Intellisense : What properties are required?


Yesterday I was talking to a Simon, another super smart dev on the EF team, and he raised a big concern, one that I am sure you can all relate too:


We’ve all seen something like this:


Intellisense


And thought: “What is the bare minimum I can do here to save a Whatever?”


This “What properties are required ?” problem is particularly tricky when working with database Entities, because very often lots of the properties are nullable or server generated, but intellisense provides no clues.


Now my conversation with Simon reminded me of a couple of posts about intellisense planning I wrote on my old blog.


The basic idea was writing code with the aim of streamlining the programmers intellisense experience.


So yesterday Simon and I started having a think, and realised that perhaps Intellisense planning is the answer to this “What properties are required ?” problem too.


In fact all you need to do is this:


1) Create an interface for each entity called something like IRequiredForX, and then add only the properties you need to that interface:


i.e. something like this:


public interface IRequiredForPerson
{
    
string Firstname {get;set;}
     string Surname {get;set;}
    
Gender Gender {get;set;}
}


2) Make your class implement that interface, and (this is the key piece) add a property to return itself cast to the interface:


public class Person: IRequiredForPerson
{
    public IRequiredForPerson Required
    {
        get { return this; }
    }


Now the programmer can use intellisense to see only what is required:


BetterIntellisense


This is the sort of thing you could easily do in partial classes that extend the classes the Entity Framework creates for you. In fact, you could even write your own CodeGen to do this for you.


Never underestimate the power of intellisense, it can make all the difference.


Nifty huh?


Thanks for the idea Simon.


PS:
In case you’re wondering, no I haven’t forgotten about my statement of intent! I am working through a big list of possible ‘real world’ applications at the moment.


Expect some action on that front soon…

Comments (8)

  1. ploeh says:

    Pretty nice! Thanks for the tip :)

  2. meataxe says:

    Alex, I wonder if you might discuss why you chose person.Required to group the required properties, rather than say using person.Optional for optionals, thereby leaving required props at the root level and hiding the rest?

    I guess you could write an IOptionalForPerson in the same way as IRequiredForPerson, and require Person to implement both?

  3. AlexJ says:

    Well I suppose you could do that but, then you would have trouble filtering on the Optional Properties in LINQ. I.e.

    var f = from p in ctx.People

           where p.Mother.Firstname == "Wendy"

           select p;

    wouldn’t be possible because Mother is optional and hence would be hidden…

    and this:

    var f = from p in ctx.People

           where p.Optional.Mother.Firstname == "Wendy"

           select p;

    Wouldn’t work in things like Entities or Linq to Sql.

    And if you then said you would leave the optional properties on the root, you would be back at square one again!

    As for having both interfaces, I suppose that is an option but the question is it worth the hassle?

    Make sense?

  4. JeremyGray says:

    Since the question begs to be asked, but hasn’t been asked just yet: If these properties are required, why are you allowing the object to be constructed without them?

    I know that the Framework Design Guidelines suggest that one should use a "create-set-call" approach, but there are plenty of people who feel that "create-set-call" is actually an anti-pattern and that discussions/"solutions" like this are a smell.

  5. brainunit says:

    I think it is a non-trivial practice. Do we really need to complicate the design and do an extra overhead for such questionable advantage? Usually I use BrowsableAttribute and EditorBrowsableAttribute, but this approach is not compatible with auto generated code.

  6. AlexJ says:

    @brainunit

    The problem with EditorBrowsableAttribute is that it is all or nothing right? So the user loses access to non-required fields. It seems the attribute solution confuses not-required with ‘hidden’?

    @Jeremy

    Well in fact the Entity Framework does codegen factory methods on the type. I just like the explicit discoverability angle.

    As for create-set-call being an anti-pattern, I can see where people are coming from. I suppose the thing is a lot of the time you do have no-param constructors for a whole host of reasons (like materialization from a database for example) and so something else that helps set the required properties is still useful.

  7. JeremyGray says:

    Yup, I hear ya. What we need now is for the ORMs to jump onto parameterized constructors in a manner not unlike how the IoC containers did long ago. Doing so would let us start reducing the accessibility of default constructors and push people towards the instantiation of fully-formed objects.

  8. jaredpar says:

    Another option would be to create a static factory method named "CreateWithRequiredData" and have it take parameters for all of the necessary values.  

    The downside to the interface approach is hard to verify it’s used correctly.  There is nothing stopping the user from only setting a subset of the data.  In addition as time goes on the values may be built up over a set of function calls making it difficult to verify the developer set all of the necessary values.

    Using a factory method allows to enforce that all values are present and makes the pattern extremely easy to grep for.