Tuesday, November 12, 2013

Nullify the Whitespace

Way back in the old days of .NET 1.1 if you wanted to check whether a string was empty or null you had to perform two explicit checks:

if (input == null || input == "")

Then in .NET 2.0 Microsoft gave us the IsNullOrEmpty extension of the System.String class, which combined the two calls and made your life that much easier.

if (string.IsNullOrEmpty(input))

But what to do if you also needed to check if the string starts with an empty character?  What about the dreaded whitespace "character"?  You had to implement your own solution that checked each character in the string to see if it qualified as a whitespace character (space, tab character, linefeed character, etc.).  This isn't exactly hard, but it always left a bad taste in my mouth.  I mean, how was I supposed to know what characters to look for?  What if they changed?  Were was I supposed to put this method?

In .NET 4.0, Microsoft gave us a solution: IsNullOrWhiteSpace.  This new method checks whether the string is empty (length of 0), null, or contains only whitespace characters (more on this later).  When I looked up this new feature originally I made a mental note along the lines of "performs IsNullOrEmpty, then checks if string is blank" and went on my way, using IsNullOrWhiteSpace wherever I had previously used IsNullOrEmpty.  Of course that made sense.  IsNullOrWhiteSpace must be better because it's newer, right?

The answer is yes and no.  The obvious point that I missed was these methods check for different things.  When you only care whether the string has a value, regardless of the contents of the string then you can safely use IsNullOrEmpty.  If you absolutely have to know whether the string contains nothing but whitespace then you'll want to use IsNullOrWhiteSpace.  You're probably asking yourself why you read this far to read something you already knew, and the answer to that is because I have performance metrics to show you!

Both IsNullOrEmpty and IsNullOrWhiteSpace are string extension methods so their code is pretty straightforward.  I got to wondering how each was implemented and found that they're pretty much what you'd expect:

public static bool IsNullOrEmpty(string value)
{
    if (value != null)
        return value.Length == 0;
    else
        return true;
}

public static bool IsNullOrWhiteSpace(string value)
{
    if (value == null)
        return true;
    for (int index = 0; index < value.Length; ++index)
    {
        if (!char.IsWhiteSpace(value[index]))
            return false;
    }
    return true;
}

public static bool IsWhiteSpace(char c)
{
    if (char.IsLatin1(c))
        return char.IsWhiteSpaceLatin1(c);
    else
        return CharUnicodeInfo.IsWhiteSpace(c);
}

private static bool IsWhiteSpaceLatin1(char c)
{
    return (int) c == 32 || (int) c >= 9 && (int) c <= 13 || ((int) c == 160 || (int) c == 133);
}

public static bool IsWhiteSpace(char c)
{ 
    if (IsLatin1(c))
    {
        return (IsWhiteSpaceLatin1(c)); 
    }
 
    return CharUnicodeInfo.IsWhiteSpace(c);
}

IsNullOrEmpty is about as simple as it gets.  It essentially just encapsulates what we were doing on our own before.  Now it's an extension method that's part of the framework.

IsNullOrWhiteSpace is slightly more complex, but still pretty easy to understand.  If the argument is null, return true.  If not (there's some value in it), then iterate through each character in the string and check whether that character is a whitespace character.  If it is, return false.  If it isn't, keep going.  Since the for loop starts at the 0 index and counts up, the method will exit as soon as a non-whitespace character is encountered.  This is what got me thinking of performance.

At first glance, this looks like it could end up being a monster.  Fortunately, that's only true if your input starts with a bunch of whitespace characters.  So I did what any diligent developer would do.  I coded it and ran a test:
var stopwatch = new Stopwatch();
 
var shortStringToCheck = new string('a', 100);
var longStringToCheck = new string('a', 100000);
var shortWhitespaceString = new string(' ', 100) + 'a';
var longWhitespaceString = new string(' ', 100000) + 'a';

IsNullOrEmpty test code:
   1:  stopwatch.Start();
   2:   
   3:  for (var i = 1000000000; --i >= 0;)
   4:  {
   5:      var isEmpty = string.IsNullOrEmpty("");
   6:  }
   7:   
   8:  stopwatch.Stop();
   9:  Console.WriteLine("1 billion iterations of Null/empty string: " + stopwatch.ElapsedMilliseconds);
  10:   
  11:  stopwatch.Reset();
  12:  stopwatch.Start();
  13:   
  14:  for (var i = 1000000000; --i >= 0; )
  15:  {
  16:      var isEmpty = string.IsNullOrEmpty(shortStringToCheck);
  17:  }
  18:   
  19:  stopwatch.Stop();
  20:  Console.WriteLine("1 billion iterations of Null/100 character string: " + stopwatch.ElapsedMilliseconds);
  21:   
  22:  stopwatch.Reset();
  23:  stopwatch.Start();
  24:   
  25:  for (var i = 1000000000; --i >= 0; )
  26:  {
  27:      var isEmpty = string.IsNullOrEmpty(longStringToCheck);
  28:  }
  29:   
  30:  stopwatch.Stop();
  31:  Console.WriteLine("1 billion iterations of Null/100,000 character string: " + stopwatch.ElapsedMilliseconds);

IsNullOrWhiteSpace test code:
   1:  stopwatch.Start();
   2:   
   3:  for (var i = 1000000000; --i >= 0;)
   4:  {
   5:      var isEmpty = string.IsNullOrWhiteSpace("");
   6:  }
   7:   
   8:  stopwatch.Stop();
   9:  Console.WriteLine("1 billion iterations of Whitespace/empty string: " + stopwatch.ElapsedMilliseconds);
  10:   
  11:  stopwatch.Reset();
  12:  stopwatch.Start();
  13:   
  14:  for (var i = 1000000000; --i >= 0;)
  15:  {
  16:      var isEmpty = string.IsNullOrWhiteSpace(shortStringToCheck);
  17:  }
  18:   
  19:  stopwatch.Stop();
  20:  Console.WriteLine("1 billion iterations of Whitespace/100 character string: " +
  21:                      stopwatch.ElapsedMilliseconds);
  22:   
  23:  stopwatch.Reset();
  24:  stopwatch.Start();
  25:   
  26:  for (var i = 1000000000; --i >= 0;)
  27:  {
  28:      var isEmpty = string.IsNullOrWhiteSpace(longStringToCheck);
  29:  }
  30:   
  31:  stopwatch.Stop();
  32:  Console.WriteLine("1 billion iterations of Whitespace/100,000 character string: " +
  33:                      stopwatch.ElapsedMilliseconds);
  34:   
  35:  stopwatch.Reset();
  36:  stopwatch.Start();
  37:   
  38:  for (var i = 1000000; --i >= 0;)
  39:  {
  40:      var isEmpty = string.IsNullOrWhiteSpace(shortWhitespaceString);
  41:  }
  42:   
  43:  stopwatch.Stop();
  44:  Console.WriteLine("1 million iterations of Whitespace/100 character whitespace string: " +
  45:                      stopwatch.ElapsedMilliseconds);
  46:   
  47:  stopwatch.Reset();
  48:  stopwatch.Start();
  49:   
  50:  for (var i = 1000000; --i >= 0;)
  51:  {
  52:      var isEmpty = string.IsNullOrWhiteSpace(longWhitespaceString);
  53:  }
  54:   
  55:  stopwatch.Stop();
  56:  Console.WriteLine("1 million iterations of Whitespace/100,000 character whitespace string: " + stopwatch.ElapsedMilliseconds);

Results:




















As you can see from the results, there can be a performance hit for using IsNullOrWhiteSpace when IsNullOrEmpty will suffice, depending on how much leading whitespace you have.  Keep in mind this test performed a million iterations of string.IsNullOrWhiteSpace on a string that contained 100,000 whitespace characters followed by the letter "a" and that still only took 5.7148 minutes.  That means that on average we were able to check a 100,001 character string in 3.42875 milliseconds.

In the end, it's all about using the right method for the job.

Friday, October 11, 2013

Try Catch Finally Performance

My brother asked me an interesting question yesterday about how best to handle exceptions in his C# code.  (I think) I answered his question and then we moved to the topic of performance degradation due to the over-usage of try/catch|finally blocks.  I read a blog post by Peter Ritchie a few weeks ago about how the compiler treats code (specifically variables) within the construct, but I wanted to do some more digging.  If you're interested in what Peter had to say you can find his posts here and here.

My main line of thought was that those blog posts are pretty old and specifically discuss the x86 compiler.  Peter provides a pretty trivial bit of sample code to demonstrate his point, but by virtue of being trivial it isn't all that helpful.  I found a pretty good discussion about try/catch|finally performance here on StackOverflow, but again I felt like the example provided wasn't really indicative of a real world scenario.  My biggest issues with both sets of code is that they weren't performing any operations that might actually throw an exception.

What I mean is, we can talk all day about try/catch|finally performance and give those types of examples, but in the end that's not how we'd really use a try/catch|finally block.  I'll be honest with you: my sample isn't much better, but I think it is better.

Since my brother's question was specifically about how to handle an exception when File.Move is the bit being tried, I decided to go with that.  I wrote a simple console application that moves a file from one directory to another.  There are five separate methods I used to perform the same operation.

Note: method is used here to describe a "way" of doing something, not an actual method as the term is used in C# and other languages

In the first method I put everything inside of a try block.  Variable declaration, initialization, file moving and counter incrementing.  In the second method I put only my file moving and counter incrementing code in the try block.  In the third method I put my file moving code in the try block and the counter incrementing code in the finally block.  In the fourth method I put my file moving code in the try block and moved the counter incrementing outside of the entire try/catch|finally construct.  In the fifth method I did not use a try/catch|finally block at all.

Note: if you look at the source code below you will see that there is a sixth File.Move operation; that is there solely to move the file back to the starting folder so the loop can repeat properly


   1:  var stopwatch1 = new Stopwatch();
   2:  var stopwatch2 = new Stopwatch();
   3:  var stopwatch3 = new Stopwatch();
   4:  var stopwatch4 = new Stopwatch();
   5:  var stopwatch5 = new Stopwatch();
   6:   
   7:  var counterForNoReason = 0;
   8:   
   9:  for (var i = 0; i < 100000; i++)
  10:  {
  11:      stopwatch1.Start();
  12:      try
  13:      {
  14:          var originalPath = @"C:\Temp\";
  15:          var newPath = @"C:\Temp\TryCatchPerformanceFolder\";
  16:          var fileName = @"TryCatchPerformanceFile.txt";
  17:   
  18:          File.Move(originalPath + fileName, newPath + fileName);
  19:   
  20:          counterForNoReason++;
  21:      }
  22:      catch (Exception e)
  23:      {
  24:          Console.WriteLine(e.Message);
  25:      }
  26:      stopwatch1.Stop();
  27:   
  28:      stopwatch2.Start();
  29:   
  30:      var originalPath2 = @"C:\Temp\TryCatchPerformanceFolder\";
  31:      var newPath2 = @"C:\Temp\";
  32:      var fileName2 = @"TryCatchPerformanceFile.txt";
  34:      try
  35:      {
  36:          File.Move(originalPath2 + fileName2, newPath2 + fileName2);
  37:          counterForNoReason++;
  38:      }
  39:      catch (Exception e)
  40:      {
  41:          Console.WriteLine(e.Message);
  42:      }
  43:   
  44:      stopwatch2.Stop();
  45:   
  46:      stopwatch3.Start();
  47:   
  48:      var originalPath3 = @"C:\Temp\";
  49:      var newPath3 = @"C:\Temp\TryCatchPerformanceFolder\";
  50:      var fileName3 = @"TryCatchPerformanceFile.txt";
  51:   
  52:      try
  53:      {
  54:          File.Move(originalPath3 + fileName3, newPath3 + fileName3);
  55:      }
  56:      catch (Exception e)
  57:      {
  58:          Console.WriteLine(e.Message);
  59:      }
  60:      finally
  61:      {
  62:          counterForNoReason++;
  63:      }
  64:   
  65:      stopwatch3.Stop();
  66:   
  67:      stopwatch4.Start();
  68:   
  69:      var originalPath4 = @"C:\Temp\TryCatchPerformanceFolder\";
  70:      var newPath4 = @"C:\Temp\";
  71:      var fileName4 = @"TryCatchPerformanceFile.txt";
  72:   
  73:      try
  74:      {
  75:          File.Move(originalPath4 + fileName4, newPath4 + fileName4);
  76:      }
  77:      catch (Exception e)
  78:      {
  79:          Console.WriteLine(e.Message);
  80:      }
  81:   
  82:      counterForNoReason++;
  83:   
  84:      stopwatch4.Stop();
  85:   
  86:      stopwatch5.Start();
  87:   
  88:      var originalPath5 = @"C:\Temp\";
  89:      var newPath5 = @"C:\Temp\TryCatchPerformanceFolder\";
  90:      var fileName5 = @"TryCatchPerformanceFile.txt";
  91:   
  92:      File.Move(originalPath5 + fileName5, newPath5 + fileName5);
  93:   
  94:      stopwatch5.Stop();
  95:      counterForNoReason++;
  96:   
  97:      // move the file back to where it started so the loop can repeat
  98:      File.Move(originalPath4 + fileName4, newPath4 + fileName4);
  99:  }
 100:   
 101:  Console.WriteLine(@"Try\Catch done wrong: {0}", stopwatch1.ElapsedMilliseconds);
 102:  Console.WriteLine(@"Try\Catch done right: {0}", stopwatch2.ElapsedMilliseconds);
 103:  Console.WriteLine(@"Try\Catch done right with finally: {0}", stopwatch3.ElapsedMilliseconds);
 104:  Console.WriteLine(@"No Try\Catch at all (dangerous): {0}", stopwatch4.ElapsedMilliseconds);

So how did it all turn out?  Well, it turns out that the fastest way is to live dangerously.  Skipping the try/catch|finally construct entirely was the fastest way to achieve the File.Move operation.  Since that's not reasonable, I'll ignore those results (that was really just the control anyway).  I'll let the screenshot of the results tell the rest of the story:




So there you have it.  Definitive proof (yeah, sure) that the try/catch|finally block must be used responsibly.  Only include code that can fail inside of the try block or you'll risk sinking your program under an insurmountable load and kill performance.

Tuesday, September 17, 2013

The Meaning of Life...

The Meaning Of Life As A Software Engineer When It Comes To What You Do At Work.  I know, it's not as sexy as just saying "The Meaning of Life", but if you're honest with yourself you'd admit that you wouldn't read a blog post with such a long title if I'd gone with the whole thing.

Anyway, this post is another slight deviation from software engineering, but I still feel it's important to software engineers and it technically is an "answer I couldn't find anywhere else" so I think I'm covered here.  I'm going to discuss (read: preach to you) what it means to be a software engineer.

As a software engineer your main, and possibly only, job is to make people's lives easier and/or better.  That's it.  That's the full meaning.  But it usually isn't so clear cut when you're actually working, especially when you're working for someone else.

At various points in my career I've come across some people-who-shall-remain-nameless-but-who-signed-the-check who wanted me and my team to focus on changes that make their lives easier while ignoring changes that would make a lot of other peoples' lives a lot easier and better.

It got me thinking, though.  When we're out there in the world coding away like happy little software simians we need to always be mindful of what we're doing and what kind of value we're providing.  It's really easy (for me at least) to start to slip down the this-could-be-more-elegant hole and the I-should-make-this-reusable-now-to-plan-for-the-future path while coding.  I like to ask myself one thing: who will this help?

Answering honestly, I can say that usually when I'm starting down one of the aforementioned roads I can easily pull myself back to what is important.  And what is important?  Haven't you been paying attention?  The only important thing in software engineering is making people's lives easier.  While you're coding, ask yourself these questions:

  • Whose job will be easier by using this feature?
  • Who will no longer get calls at 3 AM when something breaks because of this feature?
  • When this feature is released who will say "THANK YOU SO MUCH!!!!"?
There are other questions, but they're all on the same vein.  Just remember that what you're coding should have value to a user.  Always.

Sunday, September 15, 2013

Hide and Seek

This is a short post, and it's only kinda related to software engineering.  It's mostly just a fun thing to do when the Internet is angrifying you (yes, angrifying is a word because I said so).  If you use Google Chrome as your browser (you can also do this in IE and probably FF, too, but the steps would be different) you can right-click on an image on a page and choose Inspect Element (you can actually inspect any element on the page, not just images).  This will bring up the developer tools windowpane.  You can then change the style attribute of the image (or whatever element) and add "display:none;".  As soon as you press <Enter> the image (or whatever element) will disappear.  It will come back if you refresh the page, but for the moment it will be gone.  Check it out in pictures below.

Find the image you want to hide (the "Make extra cash" one in this example):






Right-click on it and choose Inspect Element (at the bottom of the menu)
You'll see the developer tools section at the bottom



The image you right-clicked should be highlighted so right-click on the markup for that image in the developer tools section and choose "Add Attribute"









Type in style="display:none;" and press the <Enter> key





Observe the results.





















Celebrate with a picture of a cute kitten:




Thursday, September 12, 2013

Bundles of Joy

Bundling (as it pertains to the MVC project type in Visual Studio) is a feature that was introduced... I don't know, you're not here for a history lesson.  If you're here at all you're probably here because something hinky went wrong with your bundling and you're searching the Internet desperately for something resembling an answer.  That, or you're bored.  Hopefully the first thing, though.

We had quite the charlie foxtrot the other day when it came to bundling and the issue wasn't discovered until we went to Production.  Oh, the good times.  First things first, bundling is the process by which you can tell the runtime to combine multiple resource files (such as css or javascript) together to be requested as a single document from the server.  There's a pretty good explanation here and it even has pictures!  Essentially, if you use many css files across all pages of your site (or javascript files, or you just want to reference jquery and jquery ui together) bundling can help speed up the performance of your site by turning those multiple calls into fewer calls.  In addition to bundling them, .NET will automatically minify your files (I know for sure that it will minify your javascript files and I'm pretty sure it will do the same for your css files), which means it will shrink them down to remove pretty much all white space.  It makes them nearly impossible for you to debug so you shouldn't just minify everything all the time, but it can help performance so you should definitely minify before production.

Now on to the problem.  We have an MVC3 application, which didn't include bundling "out of the box".  Instead I had to go through a bit of a long process of Googling and slapping together some suggestions until I found something that worked, which was ultimately to add System.Web.Optimization to my project (which also includes references to WebGrease and Antlr3.Runtime in case you see those in there).  After the reference was added, I just had to implement the bundling and everything worked like a charm.  Easy, right?  What, you want pictures or something?

Fine.

Here are the references in my project before doing anything...





















This is the menu you need to use.  The nuget package manager won't actually work for this.
















Using the above menu will open the Package Manager Console, in which you should type this.









Once you do that, your references should look similar to this.





















That's the setup part.  Now to actually create and consume the bundles.  Here are the using statements from my global.asax.cs file before I changed anything.


using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Data.Entity.Infrastructure;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;

I need to add a using statement for System.Web.Optimization so it looks like this.

using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Data.Entity.Infrastructure;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Optimization;
using System.Web.Routing;

Next, we add the code to build the bundles.

protected void RegisterBundles(BundleCollection bundles)
{
    bundles.Add(new ScriptBundle("~/bundles/jquery").Include(
        "~/Scripts/jquery-1.7.1.js",
        "~/Scripts/jquery-ui-1.8.20.js",
        "~/Scripts/jquery.unobtrusive-ajax.js",
        "~/Scripts/jquery.validate-vsdoc.js",
        "~/Scripts/jquery.validate.js",
        "~/Scripts/jquery.validate.unobtrusive.js"
        ));
 
    bundles.Add(new StyleBundle("~/bundles/css").Include(
        "~/Content/Site.css"
        ));
}

That's great, but we need to actually call that method we just created.

protected void Application_Start()
{
    AreaRegistration.RegisterAllAreas();
 
    // Use LocalDB for Entity Framework by default
    Database.DefaultConnectionFactory = new SqlConnectionFactory("@Data Source=(local)");
 
    RegisterGlobalFilters(GlobalFilters.Filters);
    RegisterRoutes(RouteTable.Routes);
    RegisterBundles(BundleTable.Bundles);
}

Now that we have the bundles created we have to actually consume them.  This is in the head section of my _layout.cshtml file (note that you'll need to follow these same steps for all layouts used in your project).

<title>@ViewBag.Title</title>
<link href="@Url.Content("~/Content/Site.css")" rel="stylesheet" type="text/css" />
<script src="@Url.Content("~/Scripts/jquery-1.7.1.min.js")" type="text/javascript"></script>
<script src="@Url.Content("~/Scripts/jquery.validate.js")" type="text/javascript"></script>
<script src="@Url.Content("~/Scripts/jquery.validate.unobtrusive.js")" type="text/javascript"></script>

We make a couple of minor changes and we should be all set.

<title>@ViewBag.Title</title>
@Scripts.Render("~/bundles/jquery")
@Styles.Render("~/bundles/css")

Now, I may have told a very little lie earlier when I said "everything worked like a charm".  See, the reality is that everything appeared to have worked like a charm, but in reality was waiting like a lion at the watering hole, just waiting for me to get thirsty... or push to Production.  Apparently, Visual Studio disables the optimizations portion of bundling when the program is in debug mode.  This kinda makes sense, but it can really bite you if you don't know about it.  That's what happened to me.  I guess we deployed debug mode to our Dev, QA, and Stage environments (we used TFS build configurations to do it and I didn't have a hand in that).  When we went to Production for some reason (there's actually a long story behind "some reason", but I'm going to skip it for now) we deployed the release version of the code and we didn't use a TFS build configuration.  So when it hit Production, the optimizations kicked in and everything went to Hell in a handbasket.  Here's why:

.awesomeBackground {
    background: url(images/awesome.jpg)
}

Yup, the good ol' background image in the CSS file.  In my project I have the css files stored in /Content, which means that reference you see up there actually points to /Content/images/awesome.jpg.  But scroll back up and take a look at the code in my global.asax.cs file and you'll notice that the bundle I created is "~/bundles/css", which means when everything is minified and combined into a single file, the reference to the image will be /bundles/css/images/awesome.jpg.  You can probably guess how well that works when you don't actually have an image at /bundles/css/images/awesome.jpg; it looks awful.  But fear not!  There is a solution, and I'll even throw in a way for you to verify it's all working as expected in your Dev environment so you don't have to wait until Production to find out whether everything worked.

In order to get your image url references in your CSS files to keep their maps, you just need to name your bundle the same name as the original path.  So the updated RegisterBundles method looks like this.


protected void RegisterBundles(BundleCollection bundles)
{
    bundles.Add(new ScriptBundle("~/bundles/jquery").Include(
        "~/Scripts/jquery-1.7.1.js",
        "~/Scripts/jquery-ui-1.8.20.js",
        "~/Scripts/jquery.unobtrusive-ajax.js",
        "~/Scripts/jquery.validate-vsdoc.js",
        "~/Scripts/jquery.validate.js",
        "~/Scripts/jquery.validate.unobtrusive.js"
        ));
 
    bundles.Add(new StyleBundle("~/Content/css").Include(
        "~/Content/Site.css"
        ));
}

The difference is subtle, but really important.  I changed the name of the StyleBundle.  That allows the references to work as I expected them to.  As for how you can test this in your Dev environment (while still deploying the debug version of your code), do this.

protected void Application_Start()
{
    AreaRegistration.RegisterAllAreas();
 
    // Use LocalDB for Entity Framework by default
    Database.DefaultConnectionFactory = new SqlConnection(@"Data Source=(local)");
 
    RegisterGlobalFilters(GlobalFilters.Filters);
    RegisterRoutes(RouteTable.Routes);
    RegisterBundles(BundleTable.Bundles);
 
    BundleTable.EnableOptimzations = true;
}

Yup, that one line tells .NET to go ahead and use the optimizations.  That should be all you need to do bundling in your MVC 3 application.  Fortunately, Microsoft decided to include System.Web.Optimization in a MVC 4 project type.  They also went ahead and bundled up all the jquery stuff for us so this is all a bit moot.  Hopefully it wasn't moot for you, though.

Tuesday, September 10, 2013

The Day 4.5 Broke Our Build

If your organization is like most (including mine) you don't rush out and get the latest and greatest tools the day they come out.  In fact, I can't think of anyone who does that.  We wait until there's either a) a budget surplus (yeah, because that happens in real life) or b) a need to upgrade.  That's how we found out that .NET 4.5 can break your build... even when you're programming .NET 4.0.  Allow me to explain.

We started our application rewrite (check out TDWTF for a funny explanation of the perfect scam) a couple years ago using MVC3 and .NET 4.0.  Of course we had to upgrade to Visual Studio 2010 to do this, so we did.  The rewrite got underway and a short way into it, Visual Studio 2012, .NET 4.5, MVC 4 and TFS 2012 all came out and we collectively decided we couldn't live without all of these things.  We all got VS 2012, we upgraded the TFS server to use TFS 2012, and we started on our merry way.  We decided to delay upgrading our target framework to 4.5 and also to delay upgrading our project to an MVC 4 project, but at least we were using 2012!

Then we used TFS to build and deploy our code to our dev server for the first time.  No sweat, right?  We right-clicked and hocus-pocused and voila! the site crashed... So what happened?  Well, this was the Day 4.5 Broke Our Build, remember?  So, obviously, 4.5 broke our build.  The end.

Or not.  In case you don't know, .NET 4.5 overlays .NET 4.0 so when you install 4.5 you "lose" 4.0.  That means that even if your code targets 4.0 the build server will build everything using 4.5, if 4.5 is installed on the build server.  So the build server builds your project using the 4.5 assemblies instead of the 4.0 assemblies and pushes your final code to the deployed server so it can actually be used.  Well, if the deployed server doesn't have 4.5 installed on it... BOOM!  This is where you start to get the MissingMethodException.  Ours was something along the lines of "Environment.CurrentManagedThreadId not found", but yours may be slightly different.  The point is, developing and building with 4.5 followed by deploying to a server without 4.5 will cause a problem.  The end.

Or not.  I wouldn't leave you without a solution (or two)!  Well, I might leave you without a solution, but this blog is about keeping track of fixes I've used so that I can reference them in the future and I wouldn't leave myself without a solution.  Our solution was to deploy 4.5 to our web servers.  That worked fine and honestly didn't blow anything up; honest!  According to Marc Gravell, you could also place the reference assemblies for 4.0 on the web server in the reference assemblies folder.  Since I haven't tried that solution I can't endorse it, other than to say that Marc's answers are always helpful and (as far as I can recall) correct as well so I trust him.

That's it!  That's the story of The Day 4.5 Broke Our Build.  The End.

No, seriously this time.  That was it.

Go home now.

There's nothing else to read here.

OK, fine here's another kitten picture.

Friday, September 6, 2013

Test-Driven Development

If you're like me, you've heard of Test-Driven Development (TDD) and you're kinda interested, but you haven't put a lot of time into figuring out how to do it.  Maybe you started down the path a long time ago and just got distracted (or bored, or you saw a squirrel).  Well, I recently had good cause to figure it all out and it turns out, it's really easy to learn.

The catch with learning TDD is that (if you're like me) you have to completely change the way you code against requirements.  No big deal, right?  So let me dive in and see if I can explain it simply for you (and remember that my blog is really more about creating an online repository of my own thoughts so I can figure out what I was thinking down the road).

TDD follows a pretty basic process that can be defined as: Red, Green, Refactor.  I prefer to refer to it as Fail, Pass, Clean Up, but that's just because I like to be contrary.  I find TDD easiest when I can identify acceptance criteria of my requirements.  Now, if you do agile you might be mentally protesting (or perhaps verbally, I don't know how unstable you are) that you're not supposed to have firm requirements in agile and that is sorta true, depending on your company's interpretation and implementation of agile.  But that's beside the point.  The point is that regardless of your development methodology you must have acceptance criteria.  Without acceptance criteria how will you know when you're finished coding and how will you know whether you've met your customers' needs?  So we identify acceptance criteria.  For simplicity, let's say our acceptance criteria is "the program displays the entered name".  Once you have your acceptance criteria, you can write your test.  Wait, what?!  Yeah, you create your test based on the acceptance criteria before you write any code at all.  That's why it's called Test-Driven Development.

[TestMethod]
public void ProgramShouldDisplayEnteredName()
{
    var p = new Program();
    var input = "Engineer_Andrew";
    var output = p.DisplayName(input);
    Assert.AreEqual("Engineer_Andrew", output);
}
That test fails, and that's a good thing.  The failed test is our "Red" part.  At this point, my program compiles, but the code doesn't actually do anything.  In fact, the code just throws an exception:

internal object DisplayName(string input)
{
    throw new NotImplementedException();
}

Now that we have a failing test (and we're proud of it) we write just enough code to make it turn "Green", or pass:

internal object DisplayName(string input)
{
    return input;
}

Since this test passes, we can move on to the third step; Refactor.  This is the part where we are going to refactor our code.  If you aren't familiar with that concept, it essentially means you're going to go back and make your code cleaner and/or more efficient and/or more extensible.  It can mean a lot of things, to be honest with you.  In this case it means we're going to do some validation of our input before we return it and we're going to return a string instead of an object:

internal object DisplayName(string input)
{
    if (string.IsNullOrEmpty(input))
    {
        return "Missing Name!";
    }
 
    return input;
}

The only thing left to do is re-run the same test as before and make sure it still passes.  It is also best practice to run all of the tests in your test suite to make sure you didn't inadvertently break something else.  As long as everything passes, you've met your acceptance criteria and you can move on to the next bit of code.

This is a seriously simplified example, but even on a larger scale the method provided here still holds.  Red, Green, Refactor (Fail, Pass, Clean Up).  That's all there is to it.