Jeff W. Barnes

Ramblings on C#, WCF, and random .NET

August 2006 - Posts

Another Great WCF Resource

A couple of weeks ago, I came across an excellent WCF blog.  Actually, it is probably one of the best ones (if not the best) that I have seen so far.  It is Nicholas Allen's Indigo Blog on MSDN.  He seems to post once every weekday (Monday through Friday).  From what I have seen, he does a great job of balancing each post with enough information to be useful versus cramming too much into a single entry.

If you are remotely interested in WCF, you should subscribe to his blog right now.

Now, please excuse me while I go and curse myself for falling so far behind on WCF posts.  

<@x#v%!>

Posted: Aug 21 2006, 10:35 PM by jeff.barnes | with no comments
Filed under:
Posting from Windows Live Writer

Late last week, a beta version of Windows Live Writer was released to the general public.  Since it appears to be getting quite a bit of attention from blogs all over the web, I decided to download it myself and give it a try.  In case you don't have a clue what I am talking about, Windows Live Writer is essentially a desktop application used to compose blog posts.  It is capable of interfacing with lots of different blogging services.  For me, Community Server is of greatest interest since I use it for hosting my blog.

I won't go into a detailed review of the software since a lot of other bloggers have already done so.  There is a good one here and here.  If you have any trouble setting it up for use with a Community Server blog, then this post will probably be useful.

Overall, I think it is a very cool piece of software.  The user interface seems to be relatively simple to use and intuitive.  It isn't overloaded with too many features, which is a good thing in my opinion.  However, I am sure others will disagree.  Fortunately, there is an entire SDK avaiable to develop plug-ins for all of those that want more. 

My only complaint is the lack of tag support for Community Server 2.1.  There is already a plug-in available to support Technorati tags, but I haven't found one for Community Server.  As long as the tags have already been created, you can select one or more to associate to your blog post.  They are shown as categories in a dropdown list in the upper right corner of the screen.  However, I haven't found a way to create new tags for Community Server from within Windows Live Writer.  This could simply be an oversight of mine.  If not, I am sure it is only a matter of time until someone creates a plug-in to provide support.

I definitely like the software and expect that I will continue to work with it more extensively.  Download it and see what you think.  You might just like it.

Book Review: Software Estimation - Demystifying the Black Art

A couple of months ago, I decided to make myself start reading a minimum of one technical book per month.  The goal is to shoot for two, but I must read at least one.  As I read a book, I am going to post a review about it on the blog.  Last month, I read Framework Design Guidelines.  This month I have just finished reading Software Estimation: Demystifying the Black Art by Steve McConnell.

Obviously, McConnell is already a very well-known author from previous books that he has written such as Code Complete and Rapid Development.  Once again, he has delivered a technical masterpiece that should be required reading for anyone responsible for estimation.  All of the material is delivered in a sensible manner that is easy to comprehend.  I have gained a signficant amount of insight into the entire concept. 

The book is split into three parts.  The first part is about critical estimation concepts.  It covers a lot of important information that serves as somewhat of a primer for the remainder of the book.  McConnell does a good job clarifying the difference between an estimate, a target, and a commitment.  Even though it is sometimes easy to blur the lines between them, each one is unique and has a specific purpose.  He also covers some good information about the distinctions of accuracy and precision.  In typical conversation, these terms are often used to convey the same meaning, but they are not really the same thing, especially when it comes to a software estimate.  The section also discusses some of the important issues that influence estimation as well as problems that lead to estimation error.

The second part of the book is about essential techniques for creating estimates.  One of my favorites is what was referred to as Count, Compute, Judge.  Basically, this refers to the idea of counting as your first course of action.  If there is a way to directly count some value to provide the estimate, it is the your best option since it usually provides the most accurate result.  When you can't directly count the answer, you should compute the answer by counting something else that is related.  If you can't count or compute, you should use judgement only as a last resort as it introduces the greatest opportunity for bias and error.  A lot of this is may seem obvious, but it is often neglected in practice.  Some other estimation techniques that were examined include Calibration via Historical Project Data, Decomposition and Recomposition, Proxy-Based Estimates, Estimation by Analogy, and more.  It should also be noted that McConnell provides some guidance as to which of these techniques work best for sequential software developement and iterative software development as well as the level of accuracy (low, medium, or high) that is possible with each technique and the point(s) in the project when it is most useful (early, middle, or late).

The final part of the book is about some of the specific challenges involved with software estimation.  It covers a lot of the pros and cons of various ways to estimate size, effort, and schedule.  McConnell also gives some tips about the best manner in which to present your estimate.  He also provides some practical advice about the political atmosphere that often accompanies software development.

On a scale of one to five, I would easily give this book a five.  It is an excellent resource for practical advice about software estimation.  Anyone that is involved with estimates would benefit from reading this book.  Even if you aren't directly involved with software estimation, it would be advantageous to read this book for anyone that wants a better understanding of the ingredients of a successful project.

This was the last of the books that I had lying around waiting to be read.  I ordered three new books from Amazon earlier this week.  As soon as they arrive, I will get started reading my next one.  Here is a list of the books to give you a preview of the upcoming book reviews for the next couple of months:

Service-Oriented Architecture (SOA): A Planning and Implementation Guide for Business and Technology
Applying Domain-Driven Design and Patterns: With Examples in C# and .NET
Pro .NET 2.0 Extreme Programming

Upgraded to Community Server 2.1

I just thought I would mention that the site has been upgraded to Community Server 2.1.

Telligent is doing an awesome job with the product.  I love the new tagging features and overall usability improvements.  They definitely deserve a pat on the back for continuing to provide such rich capabilities for free via the Express Edition.  It has enabled the growth of a lot of online communities that probably would have struggled to get going without a ready-to-go platform like CS.

 Keep up the good work guys.

Maximize Performance with SqlDataReader

I recently took a closer look to compare the performance variations among some of the possible ways to interact with a SqlDataReader object (ordinal position, column name, etc).  Before you start telling me that I wasn't thorough, I never intended this to be an exhaustive, scientific analysis.  I just wanted to get a general idea of whether there is a measurable difference between some of the approaches.

For the test, I wrote a simple console application that queries for all records in the Orders table of the Northwind database (830 records in my database).  Each field in the table is loaded into local variables for every record in the result set.  I examined three different approaches to using the SqlDataReader.  For each approach, the query and load operation is executed 1000 times to achieve some measurable execution.  It should also be noted that I compiled the application in release mode for .NET 1.1 and .NET 2.0 to compare the two versions.  However, the application and database were both on my local machine.

Again, the only intent here is to get an idea of the general measurable differences.

Ordinal Position
This approach relies on the usage of the indexer property of the class to access a specific field based on its ordinal position in the result set.  It is often presumed to be the fastest approach since the position is already known and doesn't require searching the fields in the result set to obtain the value.  However, the indexer property has a return value of type object.  Therefore, it is usually necessary to cast the object to the desired type (such as string, int, etc).

Here are a couple of excerpts to illustrate this type of usage:

int orderID = ConvertDBValueToInt32(reader[0]);

public int ConvertDBValueToInt32(object value)
{
    return (DBNull.Value != value) ? Convert.ToInt32(value) : 0;
}

Get Methods
This approach involves using the plentiful Get methods of the SqlDataReader class, such as GetInt32, GetString, GetDouble, etc.  These methods do not perform any kind of conversion for you.  The underlying data must already be of the expected type.  In addition, it requires using the ordinal position as a parameter of the Get methods.  I often hear people argue that this is equivalent to the previously described ordinal position approach.

Here are a couple of excerpts to illustrate this type of usage:

int orderID = ConvertDBValueToInt32(reader, 0);

public int ConvertDBValueToInt32(SqlDataReader reader, int index)
{
    return (!reader.IsDBNull(index) ? reader.GetInt32(index) : 0);
}

Column Name
This approach also relies on the usage of the indexer property.  However, it uses the overload that accepts the column name of the field in the result set.  Rather than directly accessing the specific position in the result set, it is necessary for the SqlDataReader to search through the columns to match the names based on a string comparison.  This is obviously going to be more expensive, but I wanted to see if it was measurable. 

It should also be noted that the initial search for a match is case-sensitive.  If a match is not found, a second case-insensitive search is performed.  I tested this scenario as well using all uppercase, lowercase, and mixed case. 

Here are a couple of excerpts to illustrate this type of usage:

int orderID = ConvertDBValueToInt32(reader["OrderID"]);

public int ConvertDBValueToInt32(object value)
{
    return (DBNull.Value != value) ? Convert.ToInt32(value) : 0;
}

Test Results
To try and get a better estimation, I executed each test three times and averaged the results.  Here are the results for each version of .NET by SqlDataReader usage.  The value shown is the execution time (in seconds) for 1000 querying and loading iterations.

 .NET 1.1.NET 2.0
Ordinal Position:8.479.33
Get Methods:11.368.07
Case Sensitive:14.5112.53
Case Insensitive (All Upper):13.9312.23
Case Insensitive (All Lower):14.4712.48
Case Insensitive (Mixed):14.4812.57

As expected, ordinal position performed better than the other categories, but only in version 1.1.  Surprisingly, the get methods surpassed ordinal position in .NET 2.0.  As far as column names are concerned, there is a relatively minor discrepancy between the various cases.  However, I thought it was interesting that some of the case-insensitive variations performed better than the case-sensitive test.

This test was primarily for my own curiousity.  It wasn't necessarily intended to serve as an argument for the "best" way to use a SqlDataReader.  Personally, I prefer to use ordinal position because I had believed it to be the most efficient approach.  However, these test results have me reconsidering whether I will continue to so when working in .NET 2.0 even though it appears to be a minor difference between the get methods and ordinal position on that version of the framework. 

In many situations, you probably wouldn't even notice a visible difference in performance regardless of the manner in which you read data from a SqlDataReader.  However, it is something you should remember when you need to squeeze every bit of performance.  When in doubt, profile your code and measure the difference.  As always, make sure you understand the consequences of how you use the framework.

Avoid Boxing When Using String.Format with Value Types

If you have worked with .NET much at all, then you have undoubtedly used String.Format.  It is one of those essential functions that just makes development a lot simpler.  However, I have found that a lot of people don't realize they are introducing a boxing operation when passing value types (byte, int, double, etc) as parameters to String.Format.

If you look closely at the signature of the String.Format method, you will notice that the arguments passed for formatting are of type object.  When a value type is passed as one of the object parameters, it requires a boxing operation.  In case you didn't know, boxing is a mechanism to convert a value type to a reference type.  Value types are stored on the stack, but reference types are allocated on the managed heap.  In order for a value type to be used as an object, the runtime must allocate memory on the heap.  The value type is then copied from the stack to the heap.  This results in a reference to the value on the heap (just like any other reference type).  There is also an operation known as unboxing, which is simply the opposite (copying from the heap to the stack).

While boxing can be very convenient when you want to use a value type as a reference type, it can introduce performance degradation.  In some situations, the performance variation may be negligible.  However, if you aren't judicious with the manner in which it is used, then you may experience unnecessarily poor performance.

Here is a seemingly innocent method that uses String.Format:

public void ProcessOrder(int orderID)
{
    string message = String.Format("Started Processing Order {0}.", orderID);

    // Log Message
    // Process the Order
}

However, examining the generated IL reveals that the integer causes a boxing operation:

.method public hidebysig instance void  ProcessOrder(int32 orderID) cil managed
{
  // Code size       19 (0x13)
  .maxstack  2
  .locals init ([0] string message)
  IL_0000:  nop
  IL_0001:  ldstr      "Started Processing Order {0}."
  IL_0006:  ldarg.1
  IL_0007:  box        [mscorlib]System.Int32
  IL_000c:  call       string [mscorlib]System.String::Format(string,
                                                              object)
  IL_0011:  stloc.0
  IL_0012:  ret
}

Fortunately, it is very easy to avoid the boxing operation by using the ToString method on the integer parameter.  Here is our method with the very simple addition of the ToString method:

public void ProcessOrder(int orderID)
{
    string message = String.Format("Started Processing Order {0}.", orderID.ToString());

    // Log Message
    // Process the Order
}

After reviewing the updated IL, you can see that the boxing operation is avoided since a string (a reference type) is being passed rather than an integer (a value type). 

.method public hidebysig instance void  ProcessOrder(int32 orderID) cil managed
{
  // Code size       20 (0x14)
  .maxstack  2
  .locals init ([0] string message)
  IL_0000:  nop
  IL_0001:  ldstr      "Started Processing Order {0}."
  IL_0006:  ldarga.s   orderID
  IL_0008:  call       instance string [mscorlib]System.Int32::ToString()
  IL_000d:  call       string [mscorlib]System.String::Format(string,
                                                              object)
  IL_0012:  stloc.0
  IL_0013:  ret
}

The instantiation of a string is more efficient than the boxing operation.  It is directly created on the heap as opposed to copying the value from the stack (boxing of the integer). 

It should be noted that this also applies to similar method overloads such as Console.WriteLine.

While this particular example may be a minimal performance difference, it is still important to understand the consequences of boxing and be able to recognize situations when it occurs.



Disclaimer:The opinions and views expressed within this blog are solely my own and do not represent those of my employer or anyone else.