The best aren’t everywhere in South Africa

Posted on January 18, 2012

I’ve just finished reading Rework, a brilliant book I think every coder should read by 37Signals. The book is just generally badass, but one thing struck me in particular. The chapter is entitled “The Best Are Everywhere”

Basically its a page and a half case study on why they hire staff on skill and aptitude and not on location. They’ve created an awesome company comprised of staff literally scattered around the world. But in todays online world, its really not that big a deal, between online repo’s and build servers, VM’s, IM’s, email, phone and video chat they somehow make do.

Scott Hanselman has written several posts about his experiences as a remote employee. He’s actually got an entire section of his blog dedicated to remote work and how he gets around some of the issues he faces. It makes for interesting reading, but it also highlights the fact that he manages just fine.

Now if remote employees work fine for small companies like 37Signals and it also works fine for big companies like microsoft, what the hell is stopping the average company in south africa from following? I don’t get it at all.

It cuts out a commute, means I can work flexi time, in comfort and at home. At the end of the day it saves me money. Work doesn’t need a giant office, parking space etc etc etc. It saves work money.Surely its a win win?

But every time you go to career junction or get an email from a recruiter or see a job ad in the paper they need you to come in and fill a chair. Its things like this that make me convinced that some south african IT companies just don’t get the concept of moving forward.

You don’t build a kickass tech company by taking new tech and bogging it down with old school management techniques and bureaucracy. You don’t get really inventive, creative and fresh ideas by forcing people to wear a suit and tie and come in from 9-5 to sit in a box. And you don’t find the best people by limiting your field of vision to what you see outside your window.

 

A better way of working with HTTPContext.Session in MVC

Posted on January 18, 2012

One of the problems I’ve been having is passing session in and out of my controllers, helpers, and even models in some cases. Its been messy, and thats before I even thought about how it would work when it came to testing…

This week I sat down and came up with what I think is a pretty clean and neat implementation when it comes to dealing with session.

As always, it starts with an interface.

public interface ISessionCache
{
    T Get<T>(string key);
    void Set<T>(string key, T item);
    bool contains(string key);
    void clearKey(string key);
    T singleTon<T>(String key, getStuffAction<T> actionToPerform);
}

Now it all looks pretty standard, except for that last method. That last method, singleTon, was created simply because I’m sick and tired of using session in my get properties or wherever using the singleton pattern. Using generics and a delegate, I have made a base class to do my singleton checks for me.

Here is my aptly named delegate, its basically any method that returns T.

public delegate T getStuffAction<T>();

I marked the base class as abstract and also marked all of the ISessionCache members as abstract except for the singleTon method. Like i said, the methods nothing fancy, it just saves me some keystrokes, and cleans up my code a bit.

public abstract class BaseSessionCache : ISessionCache
{
    public abstract T Get<T>(string key);
    public abstract void Set<T>(string key, T item);
    public abstract bool contains(string key);
    public abstract void clearKey(string key);
    public virtual T singleTon<T>(String key, getStuffAction<T> actionToPerform)
    {
        if (!contains(key))
        {
            Set<T>(key, actionToPerform());
        }
        return Get<T>(key);
    }
}

Next is an in memory implementation I can use for testing purposes. It basically adds and gets stuff out of a dictionary.

public class InMemorySessionCache : BaseSessionCache
    {
        Dictionary<String, Object> _col;
        public InMemorySessionCache()
        {
            _col = new Dictionary<string, object>();
        }

        public T Get<T>(string key)
        {
            return (T)_col[key];
        }

        public void Set<T>(string key, T item)
        {
            _col.Add(key, item);
        }

        public bool contains(string key)
        {
            if (_col.ContainsKey(key))
            {
                return true;
            }
            return false;
        }

        public void clearKey(string key)
        {
            if (contains(key))
            {
                _col.Remove(key);
            }
        }
    }

And finally is my actual HTTPContext.Session implementation that I use in my live site.

public class HttpContextSessionCache : BaseSessionCache
{
    private readonly HttpContext _context;

    public HttpContextSessionCache()
    {
        _context = HttpContext.Current;
    }

    public T Get<T>(string key)
    {
        object value = _context.Session[key];
        return value == null ? default(T) : (T)value;
    }

    public void Set<T>(string key, T item)
    {
        _context.Session[key] = item;
    }

    public bool contains(string key)
    {
        if (_context.Session[key] != null)
        {
            return true;
        }
        return false;
    }
    public void clearKey(string key)
    {
        _context.Session[key] = null;
    }
}
 

Once again, pretty standard stuff.

Now lets see it all in action.

Public class FunController : Controller

{
    private ISessionCache _cache;

    public String SomethingInSession
    {
        get
        {
            //the traditional singleton pattern
            if (!_cache.contains("somekey"))
            {
                _cache.Set<String>("somekey", "somevalue");
            }

            return _cache.Get<String>("somekey");
        }

        set
        {
            _cache.Set<String>("somekey", value);
        }
    }

    public String SomethingElseInSession
    {
        get
        {
            //using the singleton method, saves you some lines of code.
            return _cache.singleTon<String>("somekey", () => "somevalue");
        }

        set
        {
            _cache.Set<String>("somekey", value);
        }
    }

    public FunController(ISessionCache cache)
    {
        _cache = cache;
    }

    public ActionResult Index()
    {
        //check if session contains someKey
        if (_cache.contains("someKey"))
        {
            //if not, add a list of string
            _cache.Set<List<String>>("someKey", new List<string>() { "im in session", "me too" });
        }

        //somekey is a strongly typed list of string
        var t = _cache.Get<List<String>>("someKey");

        //clear it out of session
        _cache.clearKey("someKey");
        return new EmptyResult();
    }
}
 

Now you can hook the interface up to your dependency injection and inject session into your controllers, helpers and whatever else you need without worrying about sacrificing your testability. Just wire up your test methods to use the in memory implementation and off you go. Yay…

Extending the ActionLink Helper in MVC

Posted on January 18, 2012

The ActionLink Helper is used to generate anchor links in your views in MVC. The problem I’ve been having is that if the action on a controller gets renamed, or a controller gets moved to a new Area, its really hard to find all of the action links that reference the action or controller and update them.

With that in mind, I created a small helper object and added an extension overload to the ActionLink method to solve this problem.

To start off, here is my ActionLink overload

public static HtmlString ActionLink(this HtmlHelper helper, LinkData data)
        {
            return System.Web.Mvc.Html.LinkExtensions.ActionLink(helper, data.LinkText, data.Action, data.Controller, data.routeValues, data.htmlAttributes);
        }

As you can see this takes in a LinkData object which looks like this

public class LinkData
    {
        public String Controller { get; set; }
        public String Action { get; set; }
        public RouteValueDictionary routeValues { get; set; }
        public Dictionary&lt;string,object&gt; htmlAttributes { get; set; }
        public String LinkText { get; set; }

        public LinkData()
        {
            this.routeValues = new RouteValueDictionary();
            this.htmlAttributes = new  Dictionary&lt;string,object&gt;();
        }

        public LinkData(String key,Object data) : this()
        {
            AddRouteData(key, data);
        }

        public LinkData(String areaName)
            : this("area", areaName)
        {

        }

        public void AddRouteData(String key, object data)
        {
            routeValues.Add(key, data);
        }

        public void AddHtmlAttribute(String key, object data)
        {
            htmlAttributes.Add(key, data);
        }

        //over ride equals method for testing
        public override bool Equals(object obj)
        {
            if (obj is LinkData)
            {
                return this.Equals((LinkData)obj);
            }

            return false;
        }

        public bool Equals(LinkData obj)
        {
            if (obj.Action != this.Action)
            {
                return false;
            }

            if (obj.Controller != this.Controller)
            {
                return false;
            }

            return true;
        }
    }

This LinkData object represents the information you need to generate an action link. Its got a controller name, an action name, the display text for the actual anchor. You can add html attributes to it, and its even got a route dictionary in case you need to pass things like area name etc in it.

Now I simply generate a helper class to generate return me an instance of LinkData. In here I put the string values for the controllername, the area name, the action name etc. This is the only place this information is entered so if it ever changes I only update it here.

public static partial class LinkDataHelper
    {

        public static LinkData PageInArea()
        {
            //return a link to an action in an area
            return linkDataLink("some linkText", "ActionName", "ControllerName", "AreaName");
        }

        public static LinkData HomePage()
        {
            //return a link with no area
            return linkDataLink("Home", "Index", "Home");
        }

        private static LinkData linkDataLink(String linkText, String action, String controller)
        {
            return new LinkData() { LinkText = linkText, Action = action, Controller = controller };
        }

        private static LinkData linkDataLink(String linkText, String action, String controller, String area)
        {
          return new LinkData(area) { LinkText= linkText, Action = action, Controller = controller};
        }
    }

Finally on a view, to create a link to the home page I simply type

@Html.ActionLink(LinkDataHelper.HomePage())

and the link to the page in the area looks like so

@Html.ActionLink(LinkDataHelper.PageInArea())

I have also added some overloads to the link helper allowing me to send in the link text I want to display, and for edit links I send in a value that gets added to the routedictionary with the appropriate key. This small amount of effort has paid off wholesale when it comes to moving controllers, renaming actions, stopping typo’s etc.

 

If you have any comments of suggestions feel free to contact me or leave your thoughts below.

Niggles with ViewData and the Html.DropDownList

Posted on January 18, 2012

Just a quick post, to serve as reference to my future self.

There is a weird niggle that catches me at least once every 6 weeks when using ViewData to populate an Html.DropDownList in a view. Here is the simple example that cost me 30 minutes this morning

List<SelectListItem> months = new List<SelectListItem>();

for (int i = 1; i < 13; i++)
{
    months.Add(new SelectListItem()
    {
    Text = System.Globalization.CultureInfo.CurrentCulture.DateTimeFormat.GetMonthName(i),
    Value = i.ToString(),
    Selected = (i == defaultMonth)
    });
}

ViewData["months"] = months;

As you can see, nothing special, I’m looping through months and adding them to a list of SelectListItems that get put into ViewData. There is one variable not shown, an int called defaultMonth that is going to be the lists selected item. On my View I have the following code.

@Html.DropDownList("months", (IEnumerable<SelectListItem>)ViewData["months"])

Its a simple one liner that creates a drop down based on my list, nothing special about it, we’ve all done something similar hundreds of times. Except that this will never ever ever show the list with your selected value, it will always show the first item. If you look at the values in debug as they are getting put into viewdata, everything is correct, and the value you want is the only value with selected set to true.

But the view will ignore it. Until you change the name of the Html.DropDownList so that it DOESN’T match the ViewData key you’re using to populate the list.

@Html.DropDownList("monthsDD", (IEnumerable<SelectListItem>)ViewData["months"])

Thats my working code….

*sigh*