2008: A personal retrospective

Guinness Draught bottle... a modern day masterpieceAh, the final day of the year. While many of you are partying the night away, I’m sitting at the computer, pondering what happened in 2008, thinking about what’s going to happen in 2009… and, as is often fitting of an evening after the house is finally quiet, enjoying the greatest invention of the modern era: the Guinness Draught bottle.

Back to reality. What were my personal highlights—and lowlights—of 2008? In no particular order…

  1. Leaving a full-time job to go back to work for myself — for the third time in ten years.
    Granted, the actual change happened in early December 2007, when I left a job with the New York Yankees to go back to being an independent consultant. Most people are amazed that someone would do such a thing, but I’ve made a bit of a history being just that person. Alas, my indy career didn’t last…
  2. Getting a full-time job and ending my days as an independent consultant — for the third time in eight years.
    It wasn’t an easy decision, but ultimately, there were a number of factors. What were those factors? In no particular order…

    1. I realized something about myself: My greatest value is not as an independent. As good as I may be as a technologist, solutions provider, consultant, developer, manager, adviser, whatever, my most notable successes have always been when I worked for someone else. Perhaps that’s because the stakes were always higher for me when I worked for the man. Perhaps it’s because I incorporate differently as a full-timer than as an independent. Either way, I realized I have to go where I am most effective: full-time labor for someone else.
    2. I burnt myself out by trying to be Superman — an ultra-involved father and a self-employed man just don’t mix. Too many very late nights doing work, then getting up too early. I was burning myself out. I’m too old for this (I turned 38 this year).
    3. The economy slowed, my clients tightened, and I found an incredible full-time opportunity at a great company: Business Intelligence Associates. In one month they have exceeded my expectations. I hope that in time they realize what my true potential is and give me as many opportunities to make an impact. Why don’t they know my true potential? Because I’ve masked it by making a major career blunder…
  3. Realizing the biggest career mistake I ever made was made nearly four years ago.
    Four years ago I had a very good job at a law firm, Kramer Levin. I reported directly to the CTO, had a great team of guys working for me, was responsible for nearly every business-critical system, and was doing an incredible job. Why did I leave? There’s lots of reasons, and they all made sense at the time… but looking back, leaving this job (I left to become — you guessed it — an independent consultant) set the stage for a nearly four-year stretch where I sabotaged my career. Four years ago I was well-positioned to be a senior technology manager (if not a small-company CTO) in four years. Instead, today, I am trying to re-establish my resume to get back to where I was four years ago. If I knew then what I know today, I’d make a different decision, but it’s water under the bridge at this point. Career damage control is a major 2009 objective.

Reading this, you probably are thinking, “How many times does this guy change jobs?” The answer: 14 times since 1992 (totaling 15 jobs). In chronological order:

(1) Sears, (2) Music Pen, (3) Sears (again), (4) independent music instructor, (5) World of Science, (6) Visiting Nurse Association, (7) Square One, (8) Merrill Lynch (as independent consultant), (9) some company name I can’t remember, (10) Merrill Lynch (as a full-timer), (11) Kramer Levin, (12) independent consultant, (13) New York Yankees, (14) independent consultant, (15) Business Intelligence Associates.

Spilled milk. It happens...Needless to say, I’ve very acclimated to change, and I’m very good at not crying over spilled milk.

Back on track… What am I looking forward to in 2009, which starts in 60 minutes?

  • A new addition to the family. My second child, another girl, is coming into my family in February. An infant, combined with a 3-year old, should keep me from sleeping, not that I sleep very well anyway.
  • A reinvigorated career. As outlined above, I’ve finally learned from some mistakes, and I’ve got a great job with a great company. That’s a lot to be optimistic about.
  • Something new to blog about. I got an idea, which will require some intense record-keeping next year, but I think it’ll be an enlightening project to share with people. (Hint: See that new “Taxes” category at the top of the page?)
  • Being older and wiser. When I was young, I thought experience meant nothing, that it was all about smarts and hard work. Now that I’m older, I know it is all about smarts and hard work — it’s just that experience is a huge part of intelligence. “He who doesn’t learn from his past is guaranteed to repeat his mistakes,” to paraphrase a famous quote. Fortunately, I’ve always had a fair degree of objective self-reflection. I just need to be more vigilant listening to it. 😉

Well, 53 minutes to go, and my Guinness is starting to get room temperature… I’ll leave you to your party, and wish you a HAPPY, HEALTHY, AND PROSPEROUS NEW YEAR!

Be cautious when using online services (or: you get what you pay for)

Earlier today (or yesterday, depending on your time zone), Ayende wrote about the consumer pitfalls of software-as-a-service (see Software as a Service is a matter of trust)… which made me think of some of my own “saas” experiences.

Back almost two years ago, CodePlex went down for a few days and suffered significant data loss when it came back up (see CodePlex: Did they forget to back up a server?). That was the last time I willingly used CodePlex for any open-source project.

I also remember some time back when I tried various online backup and synchronization tools. I tried XDrive (soon to be defunct) — which worked well until I realized it corrupted a large chunk of my documents. FolderShare (now Windows Live Sync) was impressive but had a habit of sync failures and/or deleting when it shouldn’t. (Granted FolderShare was a beta, and Live Sync is not, so many issues may be resolved.) In the end, I went with Mozy.

GMail goes down, too — which is why I sync locally with Thunderbird. Assembla has gone down a bunch of times — which is why I now use SVNRepository.com (and, before that, hosted-projects.com).

Over the years, I’ve grown to become wary of anything free or too cheap to be commercial when it comes to critical information. Many free or “beta” services should not be trusted implicitly with important data – a warning everyone should heed.

MSTest, DeploymentItem, and the frustrating RelativePathRoot setting

MSTest, Microsoft’s unit-testing framework, has the ability to deploy files to a predefined test directory via the [DeploymentItem] attribute. The documentation, however, includes this vague reference:

  • [DeploymentItem("file1.xml")] Deploys an item named file1.xml located at the RelativeRootPath. The file is deployed to the deployment root directory.
  • [DeploymentItem("file2.xml", "DataFiles")] Deploys an item named file2.xml located at the RelativeRootPath. The file is deployed to the DataFiles subdirectory of the deployment root directory.

Sounds good, but what is RelativePathRoot? It wasn’t easy to find out, but eventually I came across a post on the MSDN forums, which stated:

… it is simply the directory of the solution containing your test project.

Hmm… This is great, so long as your test project only exists in one solution — or, if in multiple solutions, all solutions are in the same folder. Unfortunately for me (and likely many others), this isn’t the case.

How can we handle situations where our test projects have deployment items, but the test projects are included in multiple solutions in different folders?

The messy but effective solution is to have more than one [DeploymentItem] attributes for each deployment item, each having a path that is relative from the solution directory. Fortunately, if the source file in a [DeploymentItem] attribute doesn’t exist, the test doesn’t fail – otherwise this workaround wouldn’t work.

In other words, if you are starting with this:

[TestMethod]
[DeploymentItem("TestFiles\MyFile.txt")]
public void MyTest() { }

You would modify it like this:

[TestMethod]
[DeploymentItem("TestFiles\MyFile.txt")]
[DeploymentItem("path_from_other_solution\TestFiles\MyFile.txt")]
public void MyTest() { }

Replace “path_from_other_solution” with the path from your alternate solution to the solution folder for the test project.

Not pretty, but it works.

Use WMI Code Creator to explore the details of WMI

One utility has paid incredible dividends over the past few days (not only because it is free): WMI Code Creator. This small Microsoft-provided gem allows you to explore the entire WMI namespace, and will generate code (C#, VB.Net, and VBScript) based on what you select.

If you’re using WMI, this utility goes right along-side the WMI reference documentation on MSDN in terms of usefulness.

‘Shutdown’ or ‘Shut Down’?

Which one is correct?

ShutDown()
or
Shutdown()

I’m not quite sure. Seems many Windows API calls reference it as Shutdown. Not being convinced, I did a Google search, and found an article on The Old New Thing that summarizes why there is confusion.

Basically, it boils down to this:

shutdown = noun

shut down = verb

So, my method is called ShutDown, because methods should be action phrases (verbs). The enum value will be Shutdown, because that’s a noun (the state of something).

Who says all those grammar classes in grade school don’t apply to programming?

Unit testing a WMI reboot

The other day I started working on a WMI wrapper that would encapsulate workstation management functionality (starting and stopping services, querying workstations, etc.). Unit testing, as always, is important, but I inevitably came to one problem.

How do you unit test a method that reboots a workstation?

The answer: Run the unit test, and if your machine starts to shut down, that means it’s the end of the workday, and your test passed. (It was already 6PM on a Friday, so such behavior was justified.)

ADO.Net SqlParameter and missing text in the output value

If you’re reading nvarchar(max) or ntext data from a SQL database using an output parameter with ADO.Net, you may find that the strings returned are one character in length, even though the field has more than one character of text.

This is happening because there is no Size property declared with your SqlParameter, which apparently tells ADO.Net to assume a size of 1. The solution, fortunately, is easy: specify a size of -1.

See the below examples which illustrate how to work around this ‘feature’.

// the following line doesn't specify a length, so the returned string will be one character long
SqlParameter badParam = new SqlParameter("@mynvarcharmax", SqlDbType.NVarChar);
badParam.Direction = ParameterDirection.Output;

// the following line resolves this by specifying a length of -1
SqlParameter goodParam = new SqlParameter("@mynvarcharmax", SqlDbType.NVarChar, -1);
goodParam.Direction = ParameterDirection.Output;

// if you are creating your SqlParameter by providing a parameter name and value,
// just specify the size after construction
SqlParameter goodParamWithValue = new SqlParameter("@mynvarcharmax", "my object value");
goodParamWithValue.Size = -1;
goodParamWithValue.Direction = ParameterDirection.Output;

// if using .Net 3.5, you can clean it up a bit, too
SqlParameter good35ParamWithValue = new SqlParameter("@mynvarcharmax", "my object value")
{
    Size = -1, Direction = ParameterDirection.Output;
}

Hope this helps someone else who finds themself with one-character strings inexplicably coming back from the database.