Pages

Thursday, 22 October 2009

DevExpress CodeRush and Refactor! Pro Review

I've been taking a look at this 2-product package from DevExpress over the last couple of weeks. These are my findings...

Pros
  • Adding cyclomatic complexity numbers to the left-hand margin of members was very nice. This gives you immediate awareness of whether your method needs to be refactored.
  • The Metrics window allows you to see any of the 8 measures for an entire class and then double click a member to dig down into the code. This I liked a lot.
  • Adding contracts to methods was reasonable.
  • Automatically greying out unused or unnecessary code (including namespaces, contexts and members) was very nice.
  • Inline ability to suppress suggestions for a varying scope was good.
  • Pull Member up. Lists parent classes to move a member to.
  • "Introduce a using statement" (to an IDisposable object) worked extremely well.
Cons
  • Initial thoughts are that it hides poorly written code and, thus, detracts from Craftsmanship.
  • I removed all the vertical connecting lines - far too messy.
  • The suggestion to make some variables inline was wrong. It makes the code harder to understand and, anyway, the compiler will do it.
  • The jump / break / return pointers are interesting and pretty, but it simply validates overly complicated code.
  • The suggestion to replacing objectName + ".sql" with string.Format("{0}.sql", objectName) is not necessary. Strings are, indeed, immutable; but you can concatenate them efficiently during the instantiation.
  • Suggestions to remove this. from variables - I didn't like that. I don't qualify methods with this, but I do for properties and fields. It would have been nice to separate the features.
  • I removed the Region Painting functions as it was less clear than VS's inbuilt features.
  • Disabled the Structural Highlighting. If you need an icon next to the word private to tell you that it's private then you really shouldn't be a developer!
  • Circular suggestions. Having converted a newed-up object to use Initialisers it then changed the suggestion to decompose it!
Wish List
  • A prompt to automatically end a #region. including the text e.g. #endregion Constructors.
  • Context-sensitive help in the Options dialog please.
  • Ability to add multiple metrics rather than just Cyclomatic Complexity or Line Count etc. to the left-hand margin of classes.
  • In the Option dialog identification of Level in the tree view would help.
  • A refactoring routine to create the protected On() method for events.
Conclusions? Well, overall, not bad at all. I thought I wouldn't like the interaction and the perceived lack of control; but it was actually pretty easy to use. It does take a while to learn. You just have to get stuck into some code and see what it suggests. Soon you'll find yourself wondering whether it can do xyz for you - normally it can. I, personally, will be keeping it.

My biggest fear is that too many of the features are there just to mask bad code design.

Tuesday, 20 October 2009

TFS 2010 Beta 2 - Basic Edition

Just a very quick to note about the new version of TFS called 'Basic'. Lots of people blogging about it but, for me, the biggest feature is it's ability to install on a non-server OS.

Very cool.

Now you can run a local copy (with all the loveliness you're used to) for all those little projects that aren't really the property of your employer!

Sunday, 18 October 2009

A Fireside Conversation

"I had a wonderful dream last night."

"Tell me more" you say as you lean a little closer.

"Well, I dreamt that I lived in this wonderful fantasy world full of unicorns and faeries. Every day was perpetual spring and the streams ran clear and cool. I had two close neighbours and each morning one would bake bread and the other would fry bacon. Disease and crime were a thing of the past. Best of all, though, was that every public member of Microsoft's entire Base Class Library now implemented an interface."

"No way!"

"Seriously, the unicorns were beautiful."

"No, I mean the bit about the interfaces."

"Really? What, you find the rest of my utopian landscape somehow more plausible?"

"Um... yes."

"Hmm..."

"But now you mention it; that would be quite something. Imagine how easy IoC and DI would become? Unit Tests would flow from our fingers like olive oil. Simple, elegant Adapter Patterns would fill the skies like flights of swallows."

"I can almost see them."

"It can't be that difficult, can it?"

[Pause]

"Anyway, another pint?"

Tuesday, 13 October 2009

Enabling Code Coverage on TFS Build Server Without VS Test Edition

Back in May 2009 I exchanged a number of emails with Buck Hodges regarding Code Coverage on my build server. Here's my original blog: Oi Microsoft, this IS part of Development!. Basically, the upshot was if you don't have Visual Studio 2008 Test Edition installed on your build server you will not be able to run Code Coverage as part of your automated builds.

Well, I've now managed it.

To be honest I'm not exactly sure how this happened! Inside my Default.TestRunConfig file I had my main (ASP.Net MVC) project enabled. Recently, I have added more projects to my solution and their respective \bin\debug\ dlls have been automatically added to the Code Coverage list of artifacts to instrument. I then noticed that Code Coverage results were appearing in the build for these new libraries. No coverage for my main project though. The final stage was to remove the Code Coverage reference to the main project and, instead, target the resultant dll.

I now have full unit testing and code coverage on my entire solution - a result that, apparently, can't happen.

Wednesday, 7 October 2009

Dependency Inversion Pattern Clarification

Given the following 2 dependancy structures...

interface IDependancy
{
}
class DefaultDependancy : IDependancy
{
}

... I have seen many Dependency Inversion (DI) patterns implemented in the follow way...

class Worker
{
    private IDependancy _dependancy;

    Worker()
        : this (null)
    {
    }

    Worker(IDependancy dependancy)
    {
        if (dependancy == null)
            _dependancy = new DefaultDependancy();
        else
            _dependancy = dependancy;
    }
}

I'm also guessing that you've probably gotten this far, thought "seems about right" and are about to flip back to see if anything new's happened on Twitter? Well, hold on - 'cos you're wrong!

The problem with the above scenario is that it doesn't correctly convey the intention of the pattern. The content of the non-default constructor is being asked to cope with two, entirely different, situations.

  1. "Did the client intentionally, and knowingly, call the default constructor" or
  2. "Did the client call the non-default constructor directly and accidentally pass in a null reference?"

This is a perfect recipe for the most wonderful 'managed' error: NullReferenceException. This will be made even more troublesome if you haven't yet switched to using small methods as you'll have no idea what's null. Enjoy!

So, here's what you should be doing ...

class Worker
{
    private IDependancy _dependancy;

    Worker()
        : this(new DefaultDependancy())
    {
    }

    Worker(IDependancy dependancy)
    {
        if (dependancy == null)
            throw new ArgumentNullException("dependancy");

        _dependancy = dependancy;
    }
}

Now we know that if the non-default constructor's sole parameter is null then it's because there's a problem. Actively throwing our own ArgumentNullException also allows us to take control of the situation and name the offending variable.<

This simple change removes any ambiguity in your code and makes your intentions abundantly clear.