Saturday 30 October 2010

Premature Optimisation is the Root of all Evil

It's hard to engage in any discussion about performance without someone bringing up the oft-quoted line of Knuth's:
“Premature optimization is the root of all evil.” - Donald Knuth
Now there is good advice in there, but it appears many programmers unfurl this phrase to emphesise a need to not concern yourself with performance. The issue is that there are several kinds of optimisation.

  • Optimisation from good design
  • Optimisation from good coding practices
  • Optimisation from measuring

Only the last of these could be considered a "premature optimisation" if you do it too early, but the others are fundamental to writing good code. Maintaining good clean coding practices is something every programmer should concentrate on for every line of code that they write and good design is something that happens before you even touch an IDE.

You should never forsake readability for performance, but if you are not able to improve the speed of your code while maintaining legibility, that would indicate a problem with either your design or your algorithms.

Thursday 12 August 2010

Converting Base10 to Base36

Here is a simple C# helper class for converting between base 10 and base 36.

public static class Base36Helper
{
    private const string Alphabet = "0123456789abcdefghijklmnopqrstuvwxyz";

    public static string Encode(int value)
    {
        if (value < Alphabet.Length)
        {
            return Alphabet[value].ToString();
        }

        var result = new StringBuilder();

        while (value != 0)
        {
            result.Insert(0, Alphabet[value % 36]);
            value /= 36;
        }

        return result.ToString();
    }

    public static int Decode(string value)
    {
        int result = 0;

        for (int i = 0, j = (value.Length - 1); i < value.Length; i++, j--)
        {
            result += Alphabet.IndexOf(value[j]) * (int)Math.Pow(36, i);
        }

        return result;
    }
}

Saturday 31 July 2010

Razor view engine and line breaks

I've been messing around with ASP.NET MVC 3 (preview 1) and one of the problems I needed to get round was how to keep line breaks in user entered text using the new Razor view engine. It turned out to be rather simple, as usual, although the solution was not immediately obvious.

Basically, Razor will automatically encode all strings as HTML, which is a great boon to security, but obviously there are situations where you want to maintain your own encoding. Well, turns out that Razor will leave the string alone if it's already a type of MvcHtmlString, which means that we can update our previous little extension method example to return an MVC string instead of a .NET one.
using System;
using System.Web.Mvc;

namespace LightBlog.Helpers
{
    public static class HtmlHelpers
    {
        public static MvcHtmlString Markup(this HtmlHelper helper, string value)
        {
            value = helper.Encode(value).Replace(Environment.NewLine, "<br / >");
            return new MvcHtmlString(value);
        }
    }
}
By returning an MVC string, Razor will leave our encoding alone, meaning we can now define which HTML tags we want to be displayed. Having done that, we just need to find a way to use our extension method from within a Razor view. This is simple however.
@inherits System.Web.Mvc.WebViewPage<LightBlog.Model.Post>
@using LightBlog.Helpers

@{
    View.Title = "View Post";
    LayoutPage = "~/Views/Shared/_Layout.cshtml";
}

<p>@Html.Markup(Model.Text)</p>
As you see all we need to do is to include a using reference to our Helpers namespace at the top of the view, then we can use our little Markup extension exactly as before!

Thursday 22 July 2010

Line breaks in ASP.NET MVC

I've been learning ASP.NET MVC recently, mainly because it's been so long since I worked as a Web developer, I'm completely out-of-touch with what's been going on in the industry over the last eight or so years. I decided it would be nice to learn ASP.NET MVC, as back in the day I was a PHP developer and had never done any ASP at all.

I'm slowly getting to grips with the whole convention of creating MVC sites and happily working through lots of little problems and issues. One problem I had was how to maintain line-breaks in text, until I figured out a neat little way to do it using a simple extension method on the HtmlHelper class.

Firstly the extension method itself, which is just a very basic find and replace operation. The only thing to remember is that you need to escape the HTML before you replace the newlines, otherwise the break-rule tags themselves will be encoded!
using System;
using System.Web.Mvc;

namespace LightBlog.Helpers
{
    public static class HtmlHelpers
    {
        public static string Markup(this HtmlHelper helper, string value)
        {
            return helper.Encode(value).Replace(Environment.NewLine, "<b r />");
        }
    }
}
Now that we have our little helper, our next problem is how to make our extension method available in an actual view. To do this we need to add the LightBlog.Helpers namespace to the list of CLR references allowed on each page. We can do this by going into the Web.config file in the main ASP.NET MVC directory and adding a new namespace item to the pages section, like this.
<pages>
  <namespaces>
    <add namespace="System.Web.Mvc" />
    <add namespace="System.Web.Mvc.Ajax" />
    <add namespace="System.Web.Mvc.Html" />
    <add namespace="System.Web.Routing" />
    <add namespace="LightBlog.Helpers"/>
  </namespaces>
</pages>
Now in our view code we can use our custom little Html.Markup method to output our text with the line-breaks intact.
<h1><%= Html.Markup(Model.Text) %></h1>

Tuesday 20 July 2010

Serializing a DateTime

I had an issue a few days ago about how to serialize a DateTime structure, as for some unbeknownst reason this is not supported by .NET. The solution was simple however, just wrap the DateTime in a class that you can serialize. We use the nifty little XmlIgnore attribute to tell the serializer to ignore our DateTime, but provide a separate string we can use to pickle and then unpickle the value.

[Serializable]
public class SerializableDateTime
{
    [XmlIgnore]
    public DateTime Value
    {
        get;
        private set;
    }

    // This is the value that actually gets serialized.
    public string SerializationValue
    {
        get
        {
            return Value.ToString();
        }
        
        set
        {
            Value = DateTime.Parse(value);
        }
    }

    public SerializableDateTime()
    : this(new DateTime())
    { }

    public SerializableDateTime(DateTime value)
    {
        Value = value;
    }
}

Relative dates

So here is some interesting code that gives you Twitter style relative dates in your application. I've written it out in the form I use it, as an extension method for the HtmlHelper class in ASP.NET MVC.

public static string Relative(this HtmlHelper helper, DateTime date)
{
    var span = DateTime.Now - date;
    var minutes = span.TotalMinutes;

    if (minutes < 0.75)
        return "less than a minute ago";
    else if (minutes < 1.5)
        return "a minute ago";
    else if (minutes < 45)
        return string.Format("{0} minutes ago", Math.Round(minutes));
    else if (minutes < 90)
        return "an hour ago";
    else if (minutes < 1440)
        return string.Format("{0} hours ago", Math.Round(Math.Abs(span.TotalHours)));
    else if (minutes < 2880)
        return "a day ago";
    else if (minutes < 43200)
        return string.Format("{0} days ago", Math.Floor(Math.Abs(span.TotalDays)));
    else if (minutes < 86400)
        return "a month ago";
    else if (minutes < 525600)
        return string.Format("{0} months ago", Math.Floor(Math.Abs(span.TotalDays / 30)));
    return string.Format("{0} years ago", Math.Floor(Math.Abs(span.TotalDays / 365)));
}


Now it is very easy in your view code to add pretty dates whenever you need them.

Blogging

They say every programmer should have a blog, so here's mine. I am a programmer, as I say, mainly working with the .NET Framework, although I also make forays into Python, Ruby and anything else which takes my fancy. We'll see if I can think of anything interesting to blog about.