This blog contains reflections and thoughts on my work as a software engineer

onsdag den 28. april 2010

MSTest results on CruiseControl using .NET 4

We’ve decided to upgrade our Visual Studio 2008 solutions to VS2010 and I had a few issues updating our buildserver – one of the most annoying problems was that the XSLT rendering the .NET 4 build output didn’t include our test results. My skills in regard of XSLT are – well, mediocre on a very good day - but I finally figured out that the namespace in (CCNET Installation folder)\webdashboard\xsl\MSTest9Report.xslt was wrong - the namespace was http://microsoft.com/schemas/VisualStudio/TeamTest/2006 and had to be changed to http://microsoft.com/schemas/VisualStudio/TeamTest/2010. Then my dear tests results were back to normal again. It caused me a bit of a headache because the XML was wellformed and the XPath was correct so it was really weird for a XSLT-n00b like me. It reminded me of the time where I used to debug Javascript by inserting “alert(‘123’)” into the code to see which if-clause got hit this time… What a great way to spend a few days at work that was  :o)

After changing the namespace everything is A-OK even though it annoys me a bit having to install Visual Studio 2010 on our buildserver in order to execute our MSTests. I haven't figured out a way to simply reference the Microsoft.VisualStudio.QualityTools.UnitTestFramework.dll assemblies - it just won't work for a number of reasons such as odd files missing, MSBuild errors and other various issues I’ve encountered while trying to hack my way through. Have anyone ever made MSTests run on a buildserver with no Visual Studio installed? Please let me know and you’ll be my friend for the day.

tirsdag den 13. april 2010

Refactoring

The software development community contains a huge amount of litterature with advices on how to “do” things. Do’s and dont’s are littered across the Internet – to be true I’ve also given birth to a few posts myself on various topics from time to time. Browsing the stuff one has written in the past can be quite an eyeopener in terms of “I-must-have-been-drunk-writing-that-piece-of-insanity-and-publishing-it-to-an-audience”… Any blogger with a decent record of blogposts across time probably has similar emotions towards their own blogposts otherwise you’re doing something wrong, I believe. You’re not learning anything and you’re definately not making enough mistakes on a daily basis. Only if you (such as myself) are doing regular f***ups on production environments and is the proud owner of www.iwanttoshootmyselfwithaslingshotforhavingreleasedthat.com – only then you’re in a position to discover new things about coding and yourself – and only then will you be able to reflect quitely upon the fact that truth is relative. What you believe today might not be what you believe in after another day at work tomorrow.

So – with that in mind it’s important for me to elaborate a bit from time to time over what I believe are rock-solid facts right now. Not tomorrow because I’ll probably screw up two or three times tonight during release and spend a few hours firefighting something which could have been avoided had I decided otherwise somewhere along the line. Then in a few years I’ll be able to look back on this post and think “Did I write that? Man, what a n00b…”.

As for now I want to tell you a bit about my thoughts on refactoring, how I think it should be done and the pitfalls I’ve fallen into while refactoring. Martin Fowler has written an almost mythological piece on refactoring and his Refactoring website is a good place to visit because there’s always new things to learn. Here goes

1: As always: Learn the basics, in this case about OO. If you don’t know the very basics such as “High coupling is bad” and don’t know when your code could benefit from an interface you won’t be able to recognize bad code from good code. Refactoring isn’t supposed to shape the code into something you alone like – that’s simply a waste of time. The overall goal is to improve overall readability and lift the quality of the code in terms that can be measured by tools such as FxCop and NDepend.

2: Refactoring is something you always do. Renaming a variable is refactoring – you don’t have to extract duplicate code into a method to qualify what you’re doing as “refactoring”. That’s also why agile tells us that “refactoring” tasks on the Sprint board is an antipattern. You should be refactoring 50% of the time while coding otherwise you’re doing something wrong.

3: Iteration, selection and statements – every line of code you’ve ever written has either been an iteration over something, a predicate or a statement. You can be aggressive refactoring iterations and statements because that’s often not very dangerous. Iterations and statements are changed when we rename and change visibility of methods, put duplicate code in base classes, replace magic numbers, consider recursion etc. That’s often not something to be afraid of. Changing behaviour however is a whole other story. You consider changing behaviour when you look at a monster of if-elseif-elseif-elseif…[snip]…else something and decide to introduce i.e. a Strategy Pattern. You also might go for refactoring that hideous substring-replace hell someone before you introduced to parse HTML strings because you know your Regular Expressions to the fingernails… I urge you to go for it but take your time writing those unittests. The reason you’re refactoring selections is that they are too complex for the average programmer to understand which is a proof to the fact that you probably don’t fully understand what the code is doing. How much of a moron are you if you actually think you can rewrite 100 lines of code you don’t understand into something smaller, prettier and still with the same behaviour intact? You can’t unless you really know what you’re doing (which you don’t) – and it is just a pain to have to explain to people on the floor why invoices are suddenly being sent twice to the wrong address because you missed something during your rewrite.

4: If you’re a C# programmer and have a pile of public methods you think nobody is using anymore – you can do three things: Delete, check in and pray. Or you could leave the methods as-is. Neither option is very good – you should deprecate the method instead and see if warnings start to pop up in other solutions. The [Obsolete] tag in C# is a tremendous efficient way of figuring out if public properties / methods / classes are being referenced anywhere outside your code. It’s perfectly safe and you can always go back and delete whatever you marked as Obsolete when you have made certain that there are no warnings appearing around your codebase.

5: Use tools. You’re not smart enough anyway. I know myself well enough to not trust myself at (almost) anything regarding code. Tools don’t lie – you ask, they respond. Ask WinGrep “I want to find .cs and .aspx files which contains ‘SomeNamespace.IWant.ToFind'” and it will find them for you. If you’re busting your brain to figure out assemblies where a piece of code could be used you should be using a tool to help you. The human brain is by far the most unreliable computer there is. You and all of the human race suck at being 100% accurate – that’s why man has built computers with software for you to use, damn it… I’ve only scratched the surface of NDepend but it has helped me already by clarifying some assumptions I had about our current codebase at work.

6: Don’t forget code readability. It’s not something which will improve your Cyclomatic Complexity level but it’s so important to be able to read your code. Really read – like a book. Your goal while programming should be to become the new Stephen King - in code. Or if a big guy with a beard from Hell is what turns you on you could always go for Martin Fowler. I’ll leave the details up to you. Beautiful code is easy to read and reveals intent. A fair amount of the refactorings suggested on Fowlers www.refactoring.com does indeed push for simple things such as renaming because readability in code is vastly underestimated as a code quality metric.

7: Know when to quit. You can keep on refactoring the same code because code isn’t perfect and can always be improved. Your choice and plans of attack changes over time because you change and mature as a person (hopefully). You can easily refactor the same piece of code over and over again over the years without improving it very much if you don’t look out. Ask yourself if it’s worth the effort. If it’s not ask yourself if you could learn something new by refactoring this piece of code. If not – ask someone if you should go for it. If that someone doesn’t nod his or her head – focus your energy elsewhere.

Until later…

Visual Studio 2010 released

VS2010 has arrived – check out this blogpost from The Hanselman  :o)

tirsdag den 16. marts 2010

Gotcha: .NET 2.0 Mainstream support expires in 2011

I was watching this InfoQ webcast yesterday (about refactoring legacy systems – good one actually, you should go see it) and along the way the support expiredate of .NET 2.0 was mentioned… I was a little surprised to know that the date has been set to 2011 so I doublechecked today and it’s not just for fun: Mainstream support expires in April 2011 with extended support until 2016.

What does it mean to us developers? Well… Nothing much really in the short run but it is a disaster waiting to happen for the enormous amount of mission critical .NET 1.1 and .NET 2.0 code in production around the globe. When Microsoft decides to deprecate a version there will be no service packs for one. That means that if i.e. new security vulnerabilities are discovered along the way Microsoft has every right to vow against a hotfix or a security update – because you knew (or should have known) well in advance that you should have planned for an upgrade to a newer framework.

For the majority of systems around it’s a small change to alter the “Target Framework” setting to a newer version of the framework and get rid of the warnings it generates. Heck: If you’ve stuck with .NET 2.0 and are still doing “foreach” every time you need to iterate over something you better get started anyway or find someone ready to pay you to do so I just need to raise the flag because if I didn’t see it coming lots of other developers haven’t seen it either. Spread the word  :o)

Related link: Microsoft Support Lifecycle Policy FAQ

torsdag den 4. februar 2010

MSTest TestCategory and System.Runtime.Caching - two .NET 4.0 lesser-known features

We've been fiddling with Visual Studio 2010 Beta 2 and .NET 4.0 for the past month at work. Along the way I've been peeking a bit in the released features and I'd thought I'd mention the two I've found here which caught me offguard because I didn't know they existed:

MSTest improvements

it seems that MSTest has adopted the Category attribute in NUnit - in the Microsoft.VisualStudio.TestTools.UnitTesting namespace in .NET 4.0 there is a TestCategory attribute for you to use if you have long-running integrationtests you don't need or want to run on your developer machine. The equivelant NUnit Category-attribute has been around for years so to the guys in Seattle: You have seen the light at last. Thank you. Up until now you were stuck with Test Lists which - well - I've never met anyone liking them and not experiencing friction when using them and my mother always told me never to speak badly in public about anyone I didn't like so the issue here is: TestCategory in MSTest are available in .NET 4.0   :o)

System.Runtime.Caching

There's a new namespace in .NET 4.0 which is System.Runtime.Caching. It basicly encapsulates the good ol' ASP.NET Cache from System.Web so you don't have to include System.Web in non-web assemblies if you want caching out of the box. I've always been irritated by having to either roll my own caching solution or including an assembly called "System.Web" in an assembly consisting of data-access only... It just looked too ugly and incoherent to me.

The namespace contains an abstract ObjectCache with a single implementation called MemoryCache. If you've ever worked with the ASP.NET cache you'll feel fine - Microsoft has for once gone with Principle of Least Surprise during this refactoring. There are CacheItem, CacheDependency, Absolute and Sliding expiration and so forth without the look and feel of an ASP.NET Web-application.... Nice one, Microsoft - I really mean it.

Feel free to put additional lesser-known features in the comments below if you have stumbled upon them and haven't heard or read about them anywhere.

onsdag den 27. januar 2010

.NET 4.0 Framework Client Profile in VS2010 causing “The type or namespace could not be found”

…that has got to be in the top 3 of long headlines on this blog for sure…

Currently at work we’re doing some work on new projects – for the fun of it we’re trying the new Visual Studio 2010 to get experiences with primarily .NET 4.0 and WCF 4.0

Today I encountered a problem which almost by half an inch drove me totally mad. I was for some reason unable to reference one of our .NET 3.5 assemblies. I got the good ol’ "The type or namespace name (insert assembly) could not be found (are you missing a using directive or an assembly reference?)” error thrown at me. Intellisense worked, but the class in question wasn’t caught by the color-coding… It seemed rather odd. I did what most sane people do: I recompiled the .NET 3.5 assembly. I deleted it and recompiled. I did a restart of VS 2010. I did a reboot of my entire machine. I went to a meeting leaving the machine to think about the trouble it was causing me - without any improvement when I returned. Finally I checked the code into our source repository and had someone else check out the flawed source and make a build just to make certain it wasn’t just me who had a problem going… It turned out the problem was consistent across machine boundaries which probably is the only reason I still have a small glitch of sanity left.

After fiddling with various options and project settings my eyes suddenly fell on the Target Framework setting. It was set to “.Net 4.0 Beta Client Profile”… What the hey – I never heard about Client Profiles before…???  I changed the target to “.NET 4.0 Beta” instead and voila – I was able to build succesfully. Lots of hair lost on the way but problem solved.

I’m posting this to spread the word - maybe I’m not able to take full advantage of Google in situations like this (I do feel I’m able to find what I am looking for in other situations though) - in this particular case all I could find was a bunch of newbie-Q&A’s on pages related to “are you missing a using directive or an assembly reference” etc. I really hope that the VS 2010 guys could be able to provide a better errorcontext since I was lead in a complete wrong direction by the user. I had my new SolidState Disc, Visual Studio 2010, Windows 7, Osama Bin Laden, the Man on the Moon and just about everyone in the office under suspicion for doing hanky-panky with my machine because the error made absolutely no sense what so ever.

Read more about Client Profiles here – it seems like you have to explicitly reference assemblies in configuration but I haven’t dug into it so please correct me if I’m way off on that one.

mandag den 14. december 2009

Optimizing website performance: Using ASP.NET Webcontrols to combine your CSS and JS files

So – this month we’ve been going through a performance optimization based on the suggestions provided by YSlow. There is no absolute truth in performance so the suggestions provided by YSlow should be put in a context but it is great for inspiration and lots of the advices proposed do make a lot of sense.

Untitled

One of the things we’ve pinpointed was the massive amount of files needed to load our front page (50+) so we are working on sprites as replacement for single files and I’ve been working on a solution to combine our CSS and Javascript files into one single style  The number of physical files you need to download to view a webpage is important because requests get queued and the browser consumes only two downloads in parallel – every other request sits waiting in the queue so the more requests you make the slower your website is going to be.

We needed a solution and my collegue proposed an ASP.NET Webcontrol which would act as a placeholder for our styles. After 2 days of work I came up with control made for for CSS and Javascript files which can:

  • Combine any number of CSS /Javascript files into one combined file
  • Output either combined file or single files (debug mode)
  • Removes whitespace if needed
The control ended up like the following snippet:
   <cc1:StaticFileCollection runat="server" ID="cssCollection" StaticFileType="CSS" Outputfile="/css/FrontpageAspxCssCollection.css" TrimWhiteSpace="true">      
    <cc1:StaticFile ID="StaticFile1" runat="server" Url="/script/ext-2.0/resources/css/form.css"  />
    <cc1:StaticFile ID="StaticFile2" runat="server" Url="/script/ext-2.0/resources/css/combo.css"  />
    <cc1:StaticFile ID="StaticFile3" runat="server" Url="/css/global.css"  />
    <cc1:StaticFile ID="StaticFile4" runat="server" Url="/css/article.css"  />
    <cc1:StaticFile ID="StaticFile5" runat="server" Url="/css/boxes.css"  />
    <cc1:StaticFile ID="StaticFile6" runat="server" Url="/css/ext-overrides.css"  />       
</cc1:StaticFileCollection>



What happens on PreRender is that every StaticFile is being opened and placed in a StringBuilder. It is being output in the file “/css/FrontpageAspxCssCollection.css” if the size has changed (that means that one of the sourcefiles have been altered, i.e. during development). A reference to /css/FrontpageAspxCssCollection.css is written in a Literal control. Plain and simple – no magic attached. So if you place the StaticFileCollection above in you <head> section of your webpage what you get back is this:

<link href="/css/FrontpageAspxCssCollection.css" rel="stylesheet" type="text/css">

…where the FrontPageAspxCssCollection.css is all your StaticFile’s combined into one single, physical file.

The code works for both Javascript and CSS styles. Enjoy   :o)

    [ToolboxData("<{0}:StaticFile runat=\"server\"></{0}:STATICFILE>")]
public class StaticFile : WebControl
{
public string Url { get; set; }

public override bool Visible
{
get
{
return false;
}
set
{
base.Visible = value;
}
}
}



[ToolboxData("<{0}:StaticFileCollection runat=\"server\"></{0}:StaticFileCollection>")]
public class StaticFileCollection : PlaceHolder
{
    private string _staticFileType;
    public string StaticFileType { get { return _staticFileType.ToLower();} set { _staticFileType = value;} }
    public bool TrimWhiteSpace { get; set; }
    public bool Debug { get; set; }
    public string Outputfile { get; set; }
    protected override void OnPreRender(EventArgs e)
    {        
        if (!CheckInput())
            return;
        if (Debug)           
            DoNotRenderCombinedFile();                       
        else                   
            RenderCombinedFile();


        base.OnPreRender(e);
    }

    /// <summary>
    /// Render every file in separate
    /// </summary>
    private void DoNotRenderCombinedFile()
    {
        var controls = new List<Control>();
        foreach (var control in Controls)
        {
            var c = control as StaticFile;
            controls.Add(new LiteralControl(GetScriptReference(c.Url)));
        }
        controls.ForEach(x => Controls.Add(x));
    }
    /// <summary>
    /// Render all files combined to OutputFile
    /// </summary>
    private void RenderCombinedFile()
    {
        var combinedFileString = CollectFileContent();
        string outputFile = HttpContext.Current.Server.MapPath("/" + Outputfile);
        //Get current file
        string currentContent = string.Empty;
        var currentFile = new FileInfo(outputFile);
        if (currentFile.Exists)
        {
            using (var sr = currentFile.OpenText())
                currentContent = sr.ReadToEnd();
        }
        if (TrimWhiteSpace)
        {
            var r = new Regex("\\s+", RegexOptions.Multiline);
            combinedFileString = r.Replace(combinedFileString, @" ");
        }
        //Only create new file if content has changed to maintain timestamp (avoid download to client on every hit)
        if (currentContent.Length != combinedFileString.Length)
        {              
            using (var sw = new StreamWriter(outputFile))
            {
                sw.Write(combinedFileString);
                sw.Close();
            }
        }
        Controls.Add(new LiteralControl(GetScriptReference(Outputfile)));       
    }
    private string CollectFileContent()
    {
        var cssBuilder = new StringBuilder();
        DateTime begin = DateTime.Now;
        foreach (var control in Controls)
        {
            FileInfo fi = GetFileInfoObject(control);
            using (var content = fi.OpenText())
            {
                cssBuilder.Append(string.Format("/*** {0} start ***/", fi.Name));
                cssBuilder.Append(content.ReadToEnd());
                cssBuilder.Append(string.Format("/*** {0} end ***/", fi.Name));
                cssBuilder.Append("");
            }
        }
        return cssBuilder.ToString();
    }
    private FileInfo GetFileInfoObject(object control)
    {
        var c = control as StaticFile;
        if (c == null)
            throw new ArgumentException("Only StaticFile controls can be childresn to a StaticFileCollection");
        var fi = new FileInfo(HttpContext.Current.Server.MapPath(c.Url));
        if (!fi.Exists)
            throw new ArgumentException(c.Url + " does not exist!");
        if (fi.Extension.ToLower() != "." + StaticFileType)
            throw new ArgumentException(string.Format("{0} is not of type {1}", c.Url, StaticFileType));
        return fi;
    }
    private string GetScriptReference(string url)
    {
        //Not so nice... But a strategy pattern impl. is way overkill
        string str = string.Format("<link type=\"text/css\" rel=\"stylesheet\" href=\"{0}\" />", url);
        if (StaticFileType.Equals("js"))
            str = string.Format("<script type=\"text/javascript\" src=\"{0}\" />", url);
        return str;           
    }


    private bool CheckInput()
    {
        if (string.IsNullOrEmpty(Outputfile))
            throw new ArgumentNullException("Outputfile must be set on a StaticFileCollection");
        if (StaticFileType != "js" && StaticFileType != "css")
            throw new ArgumentNullException("StaticFileType should be either JS eller CSS");
        return true;
    }
}