Nerdy tidbits from my life as a software engineer

Tuesday, November 25, 2008

Reading Metadata From Enumerations

Say you define an enumeration and want to associate some metadata with its values:

/// <summary>
/// This enumeration holds all of the properties and their identifiers
/// </summary>
public enum EPropertyIDs
{
    [CustomAttribute]
    SomePropertyID1,

    [CustomAttribute]
    SomePropertyID2,

    [CustomAttribute]
    SomePropertyID3,

}

You might think it was easy to grab these values off of a value of an EPropertyID, so you’d probably do it in a similar way to how you’d read any other metadata attribute:

/// <summary>
/// Reads the CustomAttribute associated with an EPropertyID
/// </summary>
/// <param name="propertyID">The property ID to read metadata</param>
/// <returns>An instance of CustomAttribute</returns>
public static CustomAttribute ReadMetadata(EPropertyIDs propertyID)
{            
    Type t = propertyID.GetType();
    object []propertyAttributes = t.GetCustomAttributes(typeof(PropertyDeclarationAttribute), true);

    if (propertyAttributes.Length == 0)
        throw new ArgumentException("The specified property ID does not define CustomAttribute");

    return (CustomAttribute)propertyAttributes[0];

}

But this wouldn’t do what you were probably expecting.  That’s because the type of propertyID is EPropertyIDs – not the actual value of the enumeration.  To get the metadata associated with an actual value of an enumeration, we need to get the actual field that defines that enumeration value.  To understand what I mean, check out an enumeration in ILDasm – you’ll see that an enumeration is compiled as a struct with a number of static fields.  If you want to read any metadata compiled into that enum, you’ll have to use reflection to grab the actual field that defines the value.  Then you can read the custom attribute:

/// <summary>
/// Reads the CustomAttribute associated with an EPropertyID
/// </summary>
/// <param name="propertyID">The property ID to read metadata</param>
/// <returns>An instance of CustomAttribute</returns>
public static CustomAttribute ReadMetadata(EPropertyIDs propertyID)
{            
    Type enumerationType = propertyID.GetType();
    FieldInfo fieldInfo = enumerationType.GetField(propertyID.ToString());
    object[] propertyAttributes = fieldInfo.GetCustomAttributes(typeof(CustomAttribute), true);

    if (propertyAttributes.Length == 0)
        throw new ArgumentException("The specified property ID does not define CustomAttribute");

    return (CustomAttribute)propertyAttributes[0];

}

This is a lot more cumbersome than it probably should be.  But there are cases where it’s nice to associate metadata with an enumeration value, and at least this allows you to read those data and act on them.

The Good Side of Bad Code

How many times have you inherited some crappy code?  It seems to be the norm rather than the exception.  Systems always seem to be poorly written, and the incomprehensible thing is you can’t figure out why that is.  Can it really be that so many people around the world don’t know how to write robust, reliable, well-tested software?  Don’t people go to college and learn the basic principles of software engineering?  Haven’t they gained enough experience to learn what to do and what to avoid?

I’ve pondered these questions many times over the years.  Maybe everything is a daily WTF.  Maybe there’s no such thing as good programmers – or maybe you just never seem to meet them.  But I think there’s a more logical conclusion than this.  Obviously, there are a fair number of morons in this field who are too ignorant to write good code, but there are also plenty of talented people who write crappy systems.  What’s up with that?

Well, I think there are two main reasons.  The first is preventable, and that is…to employ a good process.  Yes, all those naive project managers who never took software engineering and are more interested in meeting deadlines than producing quality software are largely responsible for the garbage that runs our world.  There are lots of instances where good programmers write crappy code because their bosses don’t understand what “unit testing” or “code coverage” means (or don’t allow them for strange reasons).  And there are plenty of people who skip design documents because, ”nobody’s going to read them anyways.”  And then there are folks who have never heard of use-cases or functional specifications.  These people are all, collectively, responsible for 90% of every bad piece of software ever written.

But there are 10% of systems out there that are written by good engineers with strong skills.  How does that happen?  I think the answer is that, despite everybody’s best intentions, often times the weaknesses in a system aren’t apparent until the whole thing has been put together.  And by the time it’s clear that your design is flawed, it’s too late to go back to the drawing board.  You can tweak your process all you want.  You can employ risk mitigation strategies like prototyping.  You can (and should) practice test-driven development.  And these techniques will help – a lot in fact - but they will not eliminate all of your problems.  Sometimes, the weakest link cannot be discovered until the entire chain has been put together.  And by that point, the most cost-effective solution is usually to let the beast linger around until it’s no longer necessary.  How many times have you heard, “Well, it seemed like a good idea at the time!

But here’s the good news: a crappy system often gives you the knowledge necessary to refactor it so that it’s no longer crappy.  And now that you know what works and what doesn’t work, you’ll be far less likely to make the same mistake twice.  Now, with the benefit of hindsight and a few years of painful maintenance and testing behind you, you can revisit the project and give yourself an opportunity to do it properly.  So the problem was your object-relational-mapping?  That’s awesome!  Now you know what was wrong with your original design!  Now you can make it work the way you intended it to work the first time!

(It’s just too bad you weren’t able to figure that out two years ago.  Oh well.)

The problem of course is that this requires everybody to admit that they made some mistakes.  And it also requires everybody to agree that it’s worth the investment to fix the problem before it gets too large.  And that’s usually not so easy to do.  But if you ever need to look on the bright side of bad code, maybe this will lift your spirits.

Friday, November 21, 2008

Type Hinting With Dynamics (Wouldn’t That Be Nice?)

I’ve blogged a little bit before about one of the big problems I foresee with dynamics, being that you loose all strong typing by using them – even if you know ahead of time what methods you will be invoking on a dynamic type.  Of course this is the tradeoff you get for using dynamic types, but it seems like a smart idea to give developers a way to pseudo-strong-type something at compile time, even if the CLR is determining what gets invoked at runtime.

For instance, lets say I have a dynamically generated type that I want to invoke using a dynamic.  I might have a class with a property that lets a consumer of that class set the dynamic instance, like this:

public dynamic SomeDynamic
{
  get;
  set;
}

public void Whatever()
{
  this.SomeDynamic.DoSomething();
}

It doesn’t matter what type SomeDynamic is.  Maybe it’s some COM object; maybe it just an arbitrary C# object.  Who cares.  But if I’m expecting that, whatever type SomeDynamic is, it has a method called DoSomething that takes no arguments, it would really be nice if I could somehow declare that expectation into my code explicitly.  That way I could (potentially) avoid runtime errors when people set SomeDyanamic to be an object that doesn’t define a method called DoSomething.  And, perhaps even more importantly, I can help myself by allowing intellisense to suggest methods and arguments for me after I type “.”.  This way, if I compile:

public void Whatever()
{
this.SomeDynamic.DoesNotExist(bogusArg1, bogusArg2); }

I can get a warning that lets me fix the problem ahead of time.  The way I envision this working is by changing the dynamic’s declaration to something like this:

public dynamic<ISomeInterface> SomeDynamic
{
  get;
  set;
}

…or maybe even…

public [TypeHint(typeof(ISomeInterface))] dynamic SomeDynamic
{
  get;
  set;
}

It seems awfully sad to me that I will loose the ability to catch things as trivial as spelling errors until I run my code.  They do happen, after all, especially without the help of intellisense.  Wouldn’t it be nice if we could check for them before-hand?

So…That’s Where it Should Be (I Think)

There’s a reason I can’t find System.Dynamics: I don’t think it exists!  From the code samples up on MSDN that came out of the PDC, it looks to me like the IDynamic interface is going to live in System.Scripting.Actions (or something like that).  The code samples in the IDynamicObject example look like it’s got an interface that looks something like this:

public virtual object GetMember(GetMemberAction action);
public virtual void SetMember(SetMemberAction action, object value);
public virtual bool DeleteMember(DeleteMemberAction action);
public virtual object Call(CallAction action, params object[] args);
public virtual object Convert(ConvertAction action);
public virtual object Create(CreateAction action, params object[] args);
public virtual object Invoke(InvokeAction action, params object[] args);
public virtual object Operation(OperationAction action, params object[] args);

(Subject to change, of course)

Since I can’t seem to find this stuff in the daily builds (I don’t think they’ve been enabled yet), I decided to start playing around with the Visual Studio 2008 CTP image that we released last month.  Hopefully, the 4.0 features are enabled in that build and I can validate some ideas with it.

By the way, I came across a pretty interesting post the other day at www.tomasp.net about reactive programming that got me thinking a little bit.  This seems like it might be the start of an interesting branch of innovation, though I think the first step is to strong type events instead of finding them via strings & reflection.

Wednesday, November 19, 2008

typeof(Boolean&) != typeof(Boolean)

Here’s something you may not have known: typeof(Boolean&) != typeof(Boolean).  So how are you supposed to know if a type you are checking is the ByRef version of something else?  The answer is: not as easily as you think.

First, some background.  Say you are trying to emit a method that has a ref parameter:

public virtual void TestWithRef(ref bool b, ref short s, ref int i, ref long l, ref float f, ref double d)
{
}

This is a stupid example, but what happens under the covers is actually pretty interesting.  First, if you grab the parameter types from this method and check them out in the debugger you get something unexpected:

"Boolean&" FullName = "System.Boolean&"
"Int16&" FullName = "System.Int16&"
"Int32&" FullName = "System.Int32&"
"Int64&" FullName = "System.Int64&"
"Single&" FullName = "System.Single&"
"Double&" FullName = "System.Double&"

Now, armed with this knowledge, how do you suppose you’d determine whether a given parameter is a bool or an int?  You might think something like this would work…

if (parameterTypes[i] == typeof(Boolean))
{
    ...
}

…but you’d be mistaken, because Boolean& is not the same as Boolean.  Fortunately, there is at least one way to make this match.  You can change the code above into this:

if (parameterTypes[i] == typeof(Boolean).MakeByRefType())
{
    ...
}

This means that you can convert any single type into a ByRef type.  But is the converse also true?  Can you convert any reference type into a non-reference type?  The answer, from what I can see is, not easily.  None of the properties in the Type struct return the underlying type.  From what I can see, this means that the only way to get the underlying type for any ByRef parameter is to do some funky string voodoo:

string paramaterTypeName = parameterTypes[i].FullName;
int andIndex = paramaterTypeName.IndexOf("&");

if (andIndex > -1)
{
    Type parameterType = Type.GetType(paramaterTypeName.Substring(0, andIndex));
    ...
}

You would think there was an easier way to get from Int32& to Int32 – wouldn’t you?

Monday, November 17, 2008

Where is System.Dynamics?

After watching Anders Hejlsberg’s presentation at the 2008 PDC, I decided to try and fool around with dynamics in the 4.0 framework.  I’ve got a whole bunch of things ready for testing.  Except that, for now anyways, I can’t figure out where they stuffed the IDynamicObject into the 4.0 libraries.  Maybe I’ve got an old drop installed on my box, but I can’t figure out where the System.Dynamics namespace is.  I want to use the IDynamicObject interface to define a mock object for unit testing, but at this point, when I compile anything that declares a dynamic:

dynamic d = new Whatever();
d.TestProperty = 10;

I get an error that makes me suspect I’m missing an assembly reference:

Error    One or more types required to compile a dynamic expression cannot be located

I’ve browsed around in the object browser for long enough to know that it’s not in the standard places (System.Core.dll, mscorlib.dll, etc.).  I hope they didn’t repeat the non-standard naming of assemblies like they did with the WPF (don’t you find it strange that the WPF assemblies are defined inside WindowsBase.dll and PresentationCore.dll?).  I’m a big believer in naming your assemblies after their root namespace; that way, you prevent situations like this.  It should be immediately obvious where System.Dynamics is: inside an assembly called System.Dynamics.dll!

Monday, November 3, 2008

Why Haven’t They Fixed This Yet?

Can somebody please explain to me why Google hasn’t fixed Gmail’s obvious loading problems yet?  For months, opening Gmail has produced an endless loop, where the loading progress bar starts, almost gets to the end, and then the page refreshes and the process starts again.  The loop never ends.  The only way to stop it is to rapidly click on the link for “slow connections” until basic client loads.  Once the client loads, you can click on the “Switch to standard view” and load the full-blown AJAX interface without any problems.  But that infinite loop on load is a real hassle that is quickly turning me away from Gmail.

In fact, if we could only get that conversation view working on Hotmail, I would be more than happy to ditch Google for good.  I can’t imagine I'm the only person who’s seen this.  It occurred at my last job, when I worked for Reveal Imaging Technologies.  And it’s happening now that I work for Microsoft.  Maybe it has something to do with corporate firewalls, I don’t know, but regardless, the onus is on the almighty Google to fix this problem.