Apr 30, 2010

5 Things you should be doing in your code but probably aren’t

This blog post is long overdue since I did the leg work for it months ago. I did a little experiment with my coworkers effectively crowd sourcing the information gathering step and I am finally distilling my findings.

At InterKnowlogy, the nature of our work changes rapidly. We are effectively a collection of custom software consultants. This means we get exposed to various different technologies, methodologies, and coding styles. Our projects range in duration from short term (4-5 weeks) to very long term (1-2 years or more). Across all these different projects I wanted to find common patterns that appear in the code. I was looking for things that could easily be changed to increase clarity, performance, and maintainability.

While the science of my approach could be debated endlessly let me preface this with “it is only a first pass.” Very simply, I asked my colleagues to take the project they were currently working on and run the built in Visual Studio code analysis tool. I asked them to send me the top one or two Code Analysis warnings that showed up most often. In some cases people ran this across multiple projects within a solution and in some cases they just ran it on the largest or most complex project in the solution. From this decidedly unscientific study I have found five common warnings that showed up consistently across projects.

All of these are simple fixes and generally acceptable, low impact fixes that would only increase clarity, robustness, or performance of your code. Now, that doesn’t mean you should blindly implement these suggestions without considering the impact of them. However, you likely have these “errors” in your codebase right now and might benefit from implementing these fixes.

1. CA1823Avoid Unused private fields

This one is easy to spot using a tool like ReSharper (R# for short). R# will gray out fields that aren’t being used anywhere (it will do the same for local variables and methods). In our case some people here are not R# fans so they don’t get this visual cue. Often times this is the result a refactoring. You will change some code in a method and the private field you were using is obsolete now but you never go back and clean up the field definition. This is a simple fix and won’t negatively affect anything. Of course it also doesn’t really hurt anything to not remove the fields but in a very large project it can help increase code clarity and reduce the work the compiler has to do to optimize away the unused fields at compile time

2. CA1305Specify IFormatProvider

This one is something I have become accustomed to doing just out of force of habit. If you call a method that has an override that accepts an IFormatProvider and don’t explicitly specify the IFormatProvider or the CultureInfo you will get this warning. Most often I see this in String.Format, String.Compare, and DateTime.Parse calls. The MSDN help has a very succinct explanation of how to deal with this error (emphasis mine):

.NET Framework members choose default culture and formatting based on assumptions that might not be correct for your code. To ensure the code works as expected for your scenarios, you should supply culture-specific information according to the following guidelines:

  • If the value will be displayed to the user, use the current culture. See CultureInfo.CurrentCulture.

  • If the value will be stored and accessed by software (persisted to a file or database), use the invariant culture. See CultureInfo.InvariantCulture.

  • If you do not know the destination of the value, have the data consumer or provider specify the culture.

Even if the default behavior of the overloaded member is appropriate for your needs, it is better to explicitly call the culture-specific overload so that your code is self-documenting and more easily maintained.

3. CA1709 & CA1704 Identifiers should be cased correctly & Identifiers should be spelled correctly

This is probably the main reason I started running CodeAnalysis consistently on my projects. I am notoriously a terrible speller and typo king (if you suffer through my blog I am sure you have noticed). CodeAnalysis does a good job detecting spelling errors in identifiers and can help you increase your code clarity and ensure you are exposing public API members with proper spelling and casing (I violated my own rule and forgot to run it on Courier and got busted as soon as someone used it and noticed on the of the public methods was misspelled). The MSDN link I provided explains how the spell checking is accomplished and how it breaks identifiers apart into logical words.

The argument on proper casing is more controversial so I will leave it up to you if you want to listen to what Code Analysis has to say about that. Is “id” or “Id” or “ID” ? (For the record it is “Id” according to Code Analysis)

4. CA1062Validate arguments of public methods

I am surprised by how often I see this one. Plain and simple, straight from MSDN: “All reference arguments that are passed to externally visible methods should be checked against null.”  Again, R# to the rescue here. It very clearly points out when you should be checking for null and gives a quick key stroke to implement the boiler plate code for you. Do you see a pattern here? R# gives you better programming habits. If you are passing in a reference argument put in a null check before you do anything else. How many times have you gotten a NullReferenceException at runtime? About a billion times and a good portion of those could be prevented by simply getting in the habit of null checking reference arguments. From MSDN:

// This method violates the rule.
public void DoNotValidate(string input)
{
if (input.Length != 0)
{
Console.WriteLine(input);
}
}

// This method satisfies the rule.
public void Validate(string input)
{
if (input == null)
{
throw new ArgumentNullException("input");
}
if (input.Length != 0)
{
Console.WriteLine(input);
}
}


5. CA1805Do not initialize unnecessarily



This one is mostly a pet peeve of mine. Again R# to the rescue here. It will simply gray out redundant initialization code. Often times, when I see redundant initialization it points out to me a fundamental misunderstanding  of how the CLR works. Again, from MSDN:



The common language runtime initializes all fields to their default values before running the constructor. In most cases, initializing a field to its default value in a constructor is redundant



If you are declaring private fields there is no need to initialize them (either in line or in the constructor) if you are just setting them to their default value. This just adds code bloat and the compiler will optimize this away anyways. To be sure you know what your fields default value is you can use the handy Default Values Table from MSDN.



 



Again, most of these issues are minor and won’t cause you grief if you don’t fix them (although CA1305 has the potential to cause some nasty issues). However, if you get in the habit of at least considering these issues and writing the code the “correct” way from the start you will reduce the overall noise in your code and increase the overall “correctness” of your codebase. Also, if you do intend to run Code Analysis on your project, fixing these five issues first will greatly reduce the number of warnings you see (at least according to my highly unscientific study).



If you didn’t notice the other pattern that emerged here it is that I am a fan of R#. It proactively helps you fix these types of issues at the time you write the code. For me, R# makes me a better programmer and helps instill better habits. Without sounding like too much of a shill for R# (too late?) I highly recommend at least trying it out and seeing if you like it. It took me about 8 months of using it before I finally “saw the light.” Now that I have I can’t live without it.



*Full Disclosure: As a Microsoft MVP JetBrains does provide me with complimentary licenses of their software, including R#. I have been using R# prior to being awarded MVP and my experience has been consistently solid throughout.

Labels: , , ,

Apr 27, 2010

Enterprise Library 5.0 Released

I am a little late to the party but I wanted to send out a quick note to congratulate the Patterns and Practices team at Microsoft on their release of Enterprise Library 5.0. I got the chance to work with the team on overhauling the configuration tool and had a blast. These guys are seriously talented engineers. If you haven’t checked out the library lately it is worth a look. We use it in almost all of our applications in one way or another and have been very satisfied with it. P&P is also nearing the release of Unity 2.0 which is also very exciting to see.  So congrats guys and keep up the good work!

Labels: , ,

Apr 26, 2010

Aliph (Jawbone) Customer Support For the Win

I purchased a Jawbone prime about 6 months ago. I have been a jawbone user since V1 and have been a huge fan of the product. By far it is the best Bluetooth headset I have owned. However, my beloved Jawbone prime decided to call it quits about a month ago. After fiddling with the charger and the headset I just couldn’t get it charge any more. I tried a different charging cable and I tried a colleagues jawbone prime in my charging cable. It became clear that my headset was dead. I contacted jawbone support to see what could be done. Honestly, I wasn’t sure what to expect. I figured the customer support would probably be outsourced to somewhere and be pretty much worthless. This has been my experience with most other tech companies so I didn’t expect different.

To my surprise I got right through to a real person and she was very knowledgeable. I explained the situation to her and she quickly offered to replace the unit, no questions asked. I was stoked. All I needed to do is send her my receipt to prove I purchased the unit and she would send me the RMA number and start the process. It gets better, she said I could simply attach a JPG of the receipt to my e-mail and off we go. That is huge for me, while I have a scanner I typically don’t save paper copies of receipts. Especially in this case, where I bought the product online. So in a matter of minutes I opened my e-mail found the original receipt and took a quick screen shot of it and away it went. Within an hour I had a response back from the same customer service rep. She gave me the RMA number and the shipping instructions and I was all set. Total phone call time was less than 5 minutes from dialing to hang up.

I couldn’t be happier. Finally a company that understands customer support. Now, I haven’t shipped my headset back to them yet (will be sending out shortly) so I can’t comment on the actual hardware RMA process but if the first impression means anything I expect this process to go very smoothly. I will update this post as soon as I finish that process and share my experiences.

UPDATE: 5/6 Seriously, these guys rock! I shipped my headset back to them via UPS. Once they received the unit they processed the return within 3 days. I had a few E-mails back and fourth with them just to send them the incoming tracking number and to let them know it was on the way. Once they processed the return they contacted me to tell me the color I originally had (black)  was out of stock but they didn’t want me to have to wait so they offered to let me chose any of the other colors they had in stock. I selected a different color and the unit was shipped out the next day. Totally awesome. All the communication was handled via e-mail, other than the the original phone call I never had to pick up a phone again. My various e-mails were responded to by 3 different customer service people, all of which were fast to respond and very accommodating. The entire thread of the conversation was kept intact across all the customer service agents and the process went incredibly smoothly. Why can’t all companies customer service be this effective?

Moral of the story? Aliph Customer Support For the Win!

Labels: , ,

Updates to Courier

I finally managed to get a few colleagues of  mine to use the Courier framework in one of their projects.  The great thing about this is I get some free testing from them. Overall things seems to be working well for them (at least that is what they tell me). However, there were a few small changes they were interested in. So I obliged and added some minor features to the framework.

1. Opt out of cached messages – Previously, there was no way to opt out of receiving cached messages. If there was a copy of a message in cache and you registered for that message you would receive the cached message. This worked for me but the suggestion was to offer a way to opt out of receiving the cache. So I added a few overrides in the Register method to allow you to specify if you want cached messages or not.

2. Broadcast / Register for “no payload” messages - This one was a bit trickier to support. The idea is you want to simply send a “notification” that something happened but you don’t actually have data to pass. After some debate on where this scenario makes sense, and why you would use Courier for this operation I decided it was best to implement the feature. So now you can do something like this:

Int32 callCount = 0;
Messenger.RegisterForMessage("Foo", () => callCount++);
Messenger.BroadcastMessage("Foo");
Assert.Equal(1, callCount);


The arguments in favor of using Courier for this (as opposed to a normal .NET event) were. One, to keep consistency throughout the project as far as message passing. If you are doing Courier in some places why not do it everywhere. Two, Courier has the advantage of being able to broadcast messages across assembly boundaries without having to couple the two assemblies tightly. With a typical .NET event you would have to know about the type of event you want, which would mean you would need a reference to the assembly where the type is defined for both the sender and the receiver. In Courier, since the messaging model is decoupled, you can leverage it to send messages without needing the type definition in each assembly.



Also, one of my colleagues contributed a Visual Studio 2008 solution so you can build 2008 assemblies in stead of the 2010.



With these updates I have decided to make this the official v 1.0 release of the framework. The 1.0 release zip file contains the release builds of Courier.dll and Courier.Rx.dll assemblies compiled against .NET4.0 and the release build of Courier.dll compiled against .NET3.5 (called Courier-vs8.dll). PDB’s are also included for all assemblies.  

Labels: ,

Apr 3, 2010

MediaRss libraries now on codeplex

I have just published a new Codeplex project: http://mediarss.codeplex.com/. This project has grown out of a larger effort I am currently working on. I had a need to read and write MediaRss files. If you aren’t familiar with the MediaRss spec it is an RSS spec originally developed by Yahoo for their video search engine. It has since been adopted by the wider community and is becoming more standardized. For details on the spec itself see here and here.

For what I am working on this format worked well for me. However, there wasn’t much out there in the way of C# libraries that did any of the heavy lifting for me. In general parsing RSS is trivial in .NET but there are a few oddities about this spec that lead me down the path of building my own library. It took a little tedious work to complete but now it as at point where it is useful to me and I felt it could be valuable to others looking for a quick solution to dealing with MediaRss files.

I leveraged the SyndicationFeed object model from .NET 3.5 to make consuming the feed feel natural to those already familiar with this model. The usage looks like this

var reader = XmlReader.Create("SampleMedia.rss");
var feed = SyndicationFeed.Load<MediaRssFeed>(reader);


What you get back is a strongly typed MediaRssFeed object. You can then treat it like you would any other SyndicationFeed object. I have also included an extension method to easily cast the Items property of the MediaRssFeed to the MediaRssItem object. To do that you would do:



var feed = SyndicationFeed.Load<MediaRssFeed>(reader);
IEnumerable<MediaRssItem> feedItems = feed.Items.AsMediaRssItems();


This lets you dive into all the properties on the items that are specific to the MediaRss spec. I still have a little more work to do to fully support the spec but it is most of the way there. The unit test project is best the place to see the samples of how to read and write using the library and how to inspect the different properties of the object. You can get the compiled binaries and / or the full source code from here. Enjoy.

Labels: , ,

Apr 2, 2010

Speaking at San Diego .NET Developers Group on 4/6

Please excuse this bit of shameless self promotion:

I will be speaking at the San Diego .NET Developers Group on April 6th, 2010. I am going to be giving a talk about technical interviewing. If you follow my blog you will recognize the topic :).

The semi ranting post I published a few months back got a lot more traffic then I expected. I thought I was just blowing off steam. However, it seemed that many other people had similar experiences and agreed, at least in part, with what I was saying.

That gave me the idea to filter out the ranting and distill down the useful bits of advice and build a talk out of it. So this talk will be my first attempt at formalizing the advice and hopefully sharing some knowledge and experience with others.

If you are local to San Diego or going to be in the area on April 6th please drop by and check out the group. The meetings are free and are always fun.

Labels: