Saturday, 19 December 2015

On side projects...again

Recently I stumbled across an interesting Stack Overflow question:

I don’t program in my spare time. Does that make me a bad developer?

The answer with the most up votes was from a user called red-dirt who makes a number of excellent points. One interesting point in particular is that a professional musician will practice a maximum of six hours day, so spending eight hours a day developing software should be plenty. This point makes sense to me. If you spend a long time doing something you should get better at it, right? By my calculations if you spend five to six years developing software you will hit the theoretical 10,000 hour mark required to become expert at something. But here’s my problem, most software developers with five to six years experience aren’t experts. I have more years experience that this and I don’t consider myself anywhere near an expert. The point I am trying to make is, while I absolutely do not think it makes you a bad software developer if you don’t program in your spare time, in my experience the best software developers I’ve worked with are the ones who have programmed in their spare time. Ultimately, I still think side projects are important.

Why aren’t all software developers experts?

So why aren’t all software developers experts? I have a few theories.

I suspect a big problem is attitude. Some developers don’t love their jobs and simply aren’t interested in learning. They are happy to repeat a single year of experience over and over.

Sometimes the work an employer gives you isn’t very interesting or challenging. Of course with a good attitude you can still learn, or failing that find a new job. But what if that aren’t many great jobs around? I live in the north east of England and while there are a lot of software development jobs, you could hardly compare it to major technology centres like London or San Francisco. There simply aren’t that many great companies to work for near where I live. Or maybe I just haven’t found them.

Perhaps your job is interesting and challenging, but is it interesting and challenging all the time? In my experience this isn’t the case. A significant percentage of work is quite mundane and doesn’t increase your skills. Again, you could argue that a new job would solve this problem, for a period of time at least.

Another problem could be training, on the job and formal. After finishing school I did a computing degree and got a software development job. University was mostly a waste of time and my first job didn’t provide me with a particularly strong set of skills. Don’t get me wrong, I enjoyed my first job and I learnt a lot, but neither the job or my degree made me a good software developer. In hindsight I feel like I stumbled around in the dark for the first four years of my career. Some might say I’m still doing that.

There are several factors that exacerbate the training problem. There is a huge amount to learn, a lot of misinformation and no clear path to becoming a good software developer. It’s not even clear what makes a good software developer! With all these problems I’m not surprised it’s difficult to become an expert in software development.

Conclusion

In conclusion, what I’m saying is that to be a really good software developer I think you need to either:

  1. Be very clever
  2. Land the perfect job with great mentors that consistently challenges you
  3. Supplement your knowledge by putting in hours out of your job

From my experience one and two are in short supply which means the majority of people are left with category three.

Tuesday, 6 October 2015

Using the TestCaseSource attribute in NUnit

I’ve used NUnit for the last few years but I only recently discovered the TestCaseSource attribute which is very useful in certain circumstances.

The scenario

Imagine you have a DeviceInformation class. It’s job is to take a user agent, parse it and provide information about the device. The class could look something like this:
public class DeviceInformation
{
    public bool IsDesktop { get; private set; }
    public bool IsMobile { get; private set; }
    public bool IsTablet { get; private set; }
    public string Manufacturer { get; private set; }

    public DeviceInformation(string userAgent)
    {
        // Some code here which sets the class properties
    }
}
One way to attack this is to create a bunch of user agents and use the TestCase attribute to confirm that multiple user agents return the same result.
private const string USER_AGENT_IPHONE_4 = "...";
private const string USER_AGENT_GALAXY_S5 = "...";
private const string USER_AGENT_LG_G4 = "...";
private const string USER_AGENT_GALAXY_TAB = "...";

[TestCase(USER_AGENT_IPHONE_4)]
[TestCase(USER_AGENT_GALAXY_S5)]
[TestCase(USER_AGENT_LG_G4)]
public void IsMobileDevice_UserAgentIsMobile_ReturnsTrue(string userAgent)
{
    Assert.IsTrue(new DeviceInformation(userAgent).IsMobile);
}

[TestCase(USER_AGENT_GALAXY_TAB)]
[TestCase(USER_AGENT_GALAXY_S5)]
[TestCase(USER_AGENT_LG_G4)]
public void IsAndroidDevice_UserAgentIsAndroid_ReturnsAndroid(string userAgent)
 {
     Assert.That(new DeviceInformation(userAgent).Manufacturer, Is.EqualTo("Android"));
 }

// More tests to cover the IsDesktop, IsTablet and Manufacturer properties here
This is a trivial example and there are already quite a few user agents. You can see that if I were to thoroughly unit test DeviceInformation I would need a lot more user agents and a lot more tests. As the number of users agents increased the number of attributes on each test would increase and the tests would become more difficult to maintain. Each time a user agent was added I’d need to scan every single test and make sure new attributes were added where appropriate.

Using the TestCaseSource attribute

From the NUnit documentation:
TestCaseSourceAttribute is used on a parameterized test method to identify the property, method or field that will provide the required arguments.
This means you can use a property, method or field to hold all of the user agent strings for a particular test rather than specify each one in it’s own attribute. Here I’ve used arrays to organise user agents into groups:
readonly string[] mobileUserAgents =
{
    USER_AGENT_IPHONE_4,
    USER_AGENT_GALAXY_S5,
    USER_AGENT_LG_G4
};

readonly string[] androidUserAgents =
{
    USER_AGENT_GALAXY_TAB,
    USER_AGENT_GALAXY_S5,
    USER_AGENT_LG_G4
};

[Test, TestCaseSource("mobileUserAgents")]
public void IsMobileDevice_UserAgentIsMobile_ReturnsTrue(string userAgent)
{
    Assert.IsTrue(new DeviceInformation(userAgent).IsMobile);
}

[Test, TestCaseSource("androidUserAgents")]
public void IsAndroidDevice_UserAgentIsAndroid_ReturnsAndroid(string userAgent)
{
    Assert.That(new DeviceInformation(userAgent).Manufacturer, Is.EqualTo("Android"));
}
Now each test only has one attribute, much better. Also, to keep the snippet short I’ve only added two groups of user agents, but for a thorough test I’d add a lot more. For example appleUserAgents, tabletUserAgents, desktopUserAgents, backBerryUserAgents, windowsPhoneUserAgents etc. Now when you want to test a new user agent you simply create a new user agent variable and add it to the appropriate arrays. The is no need to change individual tests. Easy.