A pessimist is never wrong.

I got into trouble a while back because I wrote a method that does exactly what I said it would do.  Strange huh?  I missed one important step, I trusted that the end user would respect the input requirements of my routine. 

Simply stated, if you provide me this input(preferably Hairy Potter or Genie) , my method will solve world hunger.

Unfortunately my end user provided me with a red headed step child, and as a result I returned a pyramid scam. 

 

Before I dive into code, I want to justify the title of the post.  One important lesson learned in software development is that you can’t trust anyone, and that no field tests Murphy’s Law more, than large scale system development.  When I develop I ask myself how can someone break this?  And I then make every reasonable effort to prevent a user from doing something that they shouldn’t. If I write my code to assume that everyone is illiterate, or refuses to read the documentation in my code, then I will protect myself from evil programmers.

 

Simple example which also shoes a fancy .NET 4 way of checking method pre/post conditions.

 

ConvertToCaptish_withComments

 

So my documentation clearly states a NON NULL English word,  but deush-bag Larry decided that he wanted all words so he passed null.  When he ran his program he was very angry to find out that null translates to an “Object reference” exception, which was not included in my documentation.

 

What you can’t see here is that my code assumes that the user will follow my simple request, pass me a NON-Null value.  So in my code I don’t assert that the user passed a non null value, I just TRUST that the user will follow my orders. 

So my code:

        /// <summary>
        /// This method will convert any plain english word to the Capitish language.
        /// </summary>
        /// <param name="englishWord">A non-null english word</param>
        /// <returns>Capitish equivelent word/words</returns>
        public static string[] ConvertToCapitish(string englishWord)
        {
            //1 known trouble word
            string[] matches = null;
            List<Func<string, string[]>> translators = new List<Func<string, string[]>>()
            {
                (string x)=>x.GetHomonyms(),
                (string x)=>x.GetKnownPermutations(),
                (string x)=>x.WildGuess(),

            };
            int index = 0;
            do{
                matches = translators[index++](englishWord);

            }while(matches == null || matches.Length == 0);
          
            return matches;
        }

Gracefully crashes upon null strings.  Now, this is only a simple example that I created to show you why you should always ASSERT that people are following your orders.  Pre .net 4 this was painful, you either had to use an external library, or you had to use asserts.  Either way it was painful.  Well now.. .NET 4 gives you “Code Contracts” which makes this much easier.

 

Just an aside I use mock string  Extension methods to do the actual translation:

    public static class StringExtensions
    {
        public static Dictionary<string, string[]> MagicDictionary = new Dictionary<string, string[]>();

        public static string RANDOM_WORD { get; set; }

        public static string[] GetHomonyms(this string word)
        {
            return MagicDictionary[word];
        }
        public static string[] GetKnownPermutations(this string word)
        {
            return MagicDictionary[word];
        }
        public static string[] WildGuess(this string word)
        {
            return MagicDictionary[RANDOM_WORD];
        }
    }

A quick blurb about code contracts:

Code Contracts allow me to enforce my assumptions in an easy fashion.  They provide you with static and dynmaic checking and also allow you to easily append your assumptions in auto generated documentation.  So the first cool part is that when I add code contracts it will extend my signature to enforce my constraints.  So in the above example if I add a contract that states string must be non null, and Larry tries to pass a null it wont compile!  The second piece is at runtime, if Larry decides to set a string to null and pass it, to try to get around my “check” it will also kill is attempt to foil my method.  The last piece is there are tools you can run that allow you to extract both the “method documentation” and the assumptions (pre/post conditions) that you used.    Enough words, and lets let the code speak for a bit!

An example:

I lied earlier  😉 you need to download the “static” checker for Visual Studio 2010.  All the .NET classes are there, but if you want to IDE integration/checking then you need to download from here:

http://msdn.microsoft.com/en-us/devlabs/dd491992.aspx

So I added some contracts:

        /// <summary>
        /// This method will convert any plain english word to the Capitish language.
        /// </summary>
        /// <param name="englishWord">A non-null english word</param>
        /// <param name="iReadYourPreConditions">Pass true to prove you read this</param>
        /// <returns>The possible set of capitish words</returns>
        public static string[] ConvertToCapitish(string englishWord, Boolean iReadYourPreConditions)
        {
            // Assumption
            Contract.Requires(iReadYourPreConditions == true, "Please read the pre conditions..");
            //Requirement
            Contract.Requires<ArgumentNullException>(englishWord != null, "word cannot be null");

            //1 known trouble word
            string[] matches = null;
            List<Func<string, string[]>> translators = new List<Func<string, string[]>>()
            {
                (string x)=>x.GetHomonyms(),
                (string x)=>x.GetKnownPermutations(),
                (string x)=>x.WildGuess(),

            };
            int index = 0;
            do{
                matches = translators[index++](englishWord);
                (null as String).GetHomonyms();
                englishWord.GetHomonyms();

            }while(matches == null || matches.Length == 0);
          
            return matches;
        }

And as you will see i now have 2 contracts.  A is that you read my method description, and B is that you passed me a non null English word. 

So first I thought it was neat I compiled and got a “warning” that basically said hey you wrote bad code!  I didn’t even ask for any advice!

ConvertToCaptish_withCodeContract_warning

I purposely created this issue but, obviously I should do a null check on “english word.”  What the compiler sees is (assuming englishWord is null):

 (null as String).GetHomonyms();

Which obviously will result in a crash.

 

But back to my contracts.  So assume Larry doesn’t read and just tries to use my method:

ConvertToCaptish_withCodeContract_1

Fail!  So he reads my pre conditions, and then tries:

ConvertToCaptish_withCodeContract_1_a

Then he gets bold and attempts to really trick my code:

ConvertToCaptish_withCodeContract_2

 

And fails yet again.    Well lets just say he found a way to get a null in there.. what happens then?  Well at runtime I would slap him on the wrist with a ArgumentNullException:

ConvertToCaptish_withCodeContract_runtime

 

Conclusion:

Well there is your intro guide to CodeContracts.  I didn’t really show you any truly cool stuff.  But hopefully it hints on the potential of code contracts. Unfortunately there aren’t that many good resources out there yet on CodeContracts so you have to get your hands wet… the true moral of this blog is to be defensive in your programming!  Code with a purpose, and make sure you hold people responsible for adhering to your contract.

 

PS if you are wondering what Capitish is?  Well people that know me know I sometimes have issues with mixing up common words, or just spelling things as they sound… details.. but over the years people that know me, know how to translate what I say, and what I really mean.

Take care.

Advertisements
Tagged with: , , ,
Posted in C#, LinkedIn, Microsoft

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: