Wednesday, November 24, 2010

Contract vs. Permanent

This is an odd one that I come across from time to time, and again just recently.
I work as a contractor for a client and they've expressed an interest in ensuring stability within their development team, so they had asked if I would be interested in taking a permanent position. I politely declined since the benefits of a permanent position don't coincide with my own objectives. I can definitely understand the desire to have some stability within a development team, and since I don't have any serious problem with how things are arranged, they have my assurances that I will be available essentially for as long as they need me.

The odd thing is that in talking with permanent staff, the impression of a contractor is that they're someone that can just vanish tomorrow; that being a "permanent employee" somehow indicates that the company has an investment in you, and you have an investment in them. However, when you look at the facts this doesn't hold any water, especially in the I.T. industry. How does a company invest in you? "Permanent" implies that you will always have your job through hell and high water. However every permanent employee has the exact same termination clause in their contract as I have in mine. You can be "let go" or decide to leave with 4 weeks notice. You could argue that a permanent employee would have some additional protection in the form of unfair dismissal, but no more-so than I would if I were given a six month contract which the client tried to end after just two. In either case it will be an ugly business to dispute. Companies will often offer training to permanent employees. However, in the over 15 years I have been in software development in 10 organizations/clients (7 of which as a permanent employee) I have received training twice. (1x 1-day course on advanced VB, and a 2hr course on time management.) I have only rarely seen other permanent employees actually get sent off for training or seminars. Depending on your client, a contractor can be treated to other benefits that are given to permanent staff such as inclusion in company dinners, and gifts of appreciation.

Contracting also has a bit of a myth associated with it that often rubs permanent staff the wrong way: Contractors get paid more. False, with a grain of truth. Being a contractor, especially on long-term contracts (>6 mo.) means you are exchanging most of your entitled benefits for cash. Annual leave, sick leave, paid holidays, etc. This means if you work for a full year, not taking any sick days off, as a permanent employee you are entitled to an extra 20 days pay. If you don't use it, those days are paid out when you leave and taxed at the maximum tax bracket. You won't get that extra tax back until the end of the tax year. (So in Australia, be sure to quit that permanent position in June.) In the I.T. industry and especially in smaller organizations, paid leave is rarely "convenient" to take. You're always busy, and you know that any leave you take is going to be a significant burden on the company, your co-workers, and extra urgent work to worry about when you get back. Some permanents I've worked with try to plan their vacations after the next major release, only to find that the schedule slips and that leave they've booked for months in advance now falls smack in the middle of the production roll-out. Permanent positions are kind of like an insurance policy. If you're sick or want to take some time off, your income flow stays stable. But if you don't use that, well, you might be better off with the money up front. Short term contracts will result in marginally higher rates simply because a contractor must factor in the time they need to take in-between short-term contracts in order to secure more work.

The reason I contract as a sole trader is to maximize my income to minimize my debts. There are a number of factors that I considered to reach this:
1) I have a sizable mortgage with an offset account. Offset interest savings are 100% tax free, and are valued directly against the current interest rate. (Where any other investment earnings contribute to and are taxed at your overall tax rate and Super contributions are taxed at 30% with super earnings taxed at 15%)
2) As a sole trader I invoice my client directly and weekly, collect GST and and pay it back quarterly, pay income tax annually, and do not contribute to Superannuation. (And soon I will be contributing to it again annually.)
This maximizes the amount of money I keep in my offset account working to reduce the interest my mortgage is adding up on a daily basis.
3) I'm rarely if ever sick, so sick leave isn't any value to me. (Since it's not paid out if unused, and I'm generally too ethical to "chuck a sickie".)

Because of this, contracting under this arrangement will help pay off my mortgage many years faster than if I was a permanent employee.

Thursday, November 11, 2010

Confused the compiler/runtime or what?

This was an innocent enough of a typo but it had me questioning whether the framework's string.Split() method was working with the remove empty entries option.

Line in question:
var parameterPairs = parameterValue.Split(new char['&'], StringSplitOptions.RemoveEmptyEntries).ToList();

The parameterValue being parsed was "&Token=8765"
I expected to get a result back of "Token=8765", but instead got back a value of "&Token=8765".

I was thinking was there a problem with RemoveEmptyEntries when the separator was the first character? Was there a problem with '&' as a separator? Both checked out. Then I noticed the typo. It should have been:

var parameterPairs = parameterValue.Split(new char[] {'&'}, StringSplitOptions.RemoveEmptyEntries).ToList();

And presto, the test passed. But that got me wondering, what was char['&'] resolving to? Why did the compiler allow it to compile, and why did string.Split() seem to merely ignore it at runtime?

I put in a precursor condition:
var test = new char['&'];

along with a breakpoint.

Curious...

Tuesday, November 2, 2010

Beware! The clipboard may lead you to question your sanity.

This one had me scratching my head for a good while. I was able to fix it easily enough, but getting to the bottom of just what the hell happened took a bit of digging.


The problem started because I wanted to switch a test against a certificate located on the disk to using a certificate located in a certificate store. For this test I decided to pull the certificate by serial number so I snatched the serial number from the certificate properties easily enough.

I tried this as-is and it wasn't working. So I tried removing the spaces, still no joy. So I grabbed the entire list of certificates on the machine and found the certificate to verify the serial #. The results showed the serial number in upper case, so I quickly popped a .ToUpper() on my key. NO-JOY. Ok, WTF. So I copy the serial number out of the watch results in the IDE and try again, it works.

But I couldn't leave it at that. What was wrong with my original value? I restored the changes and created a second set of checks (See first screen) and started cursing my monitor in disbelief. I lined them up, reversed the order they were called in the Find() statement, and cleaned and rebuilt the test application several times. String.Compare returns a match, .Equals returns not equals. The call to the store to Find returns a result for only the one value, regardless of which order they are executed.

The only possibility: copy and pasting the original value from the certificate dialog resulted in some unprinted Unicode character being embedded in the original string. (serial2) String.Compare ignores it, but .Equals does not. (The test1/test2/result check was just me testing my sanity that .Equals on string wasn't doing a reference equals.) To quote Sir Arthur Conan Doyle: "Once you eliminate the impossible, whatever remains, no matter how improbable, must be the truth."

Monday, November 1, 2010

Keeping up is fun.

Software development is constantly evolving. Years ago there would be years between product releases, and while there were libraries popping up every so often, there were typically a lot fewer to follow for any given project you might be working on. The pace of change was generally slower.

Today, change is constant and occurring at a significantly faster pace.On top of that, the open-source movement has meant a lot more releases of a lot more useful tools to incorporate within a project. It's easy to get left behind, or running after new versions without a chance to stop and smell the roses.

A perfect example. nUnit is a brilliant unit test framework port for .Net. I've used it for many years, but I've never really given each new version more than a passing glance. Unitl I caught a mention of a new attribute called "[TestCase]". (As opposed to the "[Test]" which denotes a test case.)

Take a case where you want to test a range of outputs such as a minimum, maximum, and assortment of values to ensure a method is working properly. This might be 4 tests or more, consisting of setup, call, and assert. For example I had 3 tests that verified formatting behaviour for a currency converter. Positive value, negative value, and zero. Scenarios like this can now be replaced by something like this:

        [TestCase(1000d, Result = "$1,000.00")]
        [TestCase(-1000d, Result = "-$1,000.00")]
        [TestCase(0d, Result = "$0.00")]
        public string EnsureConverterFormatsCurrencyValues(decimal value)
        {
            IValueConverter testConverter = new DecimalToCurrencyConverter();
            return (string)testConverter.Convert((decimal)value, typeof(decimal), null, CultureInfo.CurrentUICulture);
        }
*Sigh*... Those roses sure smell nice when you finally get a chance. Not only is it one test case (executed and reported 3 times) but it doesn't even need the Assert.Equals line. It would have been nice to have spotted this a year ago when they added it. :)

*Note: The above declaration is actual code, not a typo. The parameters on the attribute are provided as doubles (d) not decimal (m) even though the parameter type is decimal. Decimals cannot be provided via attributes (a limitation in .Net) so TestCase facilitates this translation.