It has been quite a long time since I last posted anything to my blog. It's not that I haven't thought about it or that I haven't had time (though life has been busy). I've struggled topically with what to write.
This blog was started with the intent that I would share things about my work: creating software. But, over the last year my job has been in a fairly constant state of flux with my responsibilities shifting radically from what I was doing previously.
I love being a software developer. I love the problem solving that the work entails. I love being in "the zone" while writing code. I love creating something that others find useful and I like to think that I am fairly good at it. Wishful thinking? Perhaps. But, at least one other person has thought me passable, so I choose to believe. 🙂
At present my job title is VP of Software Architecture. In my new responsibilities I still get to solve incredibly complex problems and derive a lot of satisfaction from it. In many ways the things I work on now are more intricate and stimulating than what I did previously. The only downside is that I rarely get to ride "the zone" via coding anymore.
Two years ago, if someone had described my current job to me and asked if I wanted the position, I would have turned them down outright. I derive so much pleasure and satisfaction from writing code that I could not have imagined wanting something else. I was firm (and vocal) in my commitment to avoiding "the management track." How then did I end up here?
I joined Mobile Productivity, Inc. (MPI) in January 2004. The people were great and the work was both challenging and interesting. But, after a few years I started to grow bored. Nothing had really changed, except that I wasn't creating new software anymore. I was responsible for a significant portion of our flagship product, ARGIS (since rebranded MPI Edge), but I had rewritten most of the code several times and just wasn't being stimulated the way I once was. I decided to leave MPI to go work for another startup named Podango.
Podango was a good company in many respects, but like many startups it wasn't able to thrive and closed at the end of 2008. Friends at MPI heard that I was in the job market and offered me a position. I was a bit hesitant, but a lot of new things were happening and I felt good about returning.
Internally at SRS, this period of my career is jokingly referred to as my "sabbatical."
Somewhere in all of this, MPI acquired several companies and was renamed Service Repair Solutions (SRS). We've grown from 25 people in a single office to just under 600 total (including offshore teams). The Engineering department alone has over 200 people spread across offices in Utah, Minnesota, Uruguay, Vietnam, Las Vegas and Russia.
I'm not worried about growing bored again any time soon. My job is awesome!
Note: This blog post was originally posted to an internal SRS blog on February 09, 2010. The post was intended to address specific issues, but I do strongly support the idea of "commit early and often" as a general principle.
Source Code Management
Source control is a fundamental part of software development. The benefits of using a source control management (SCM) system are numerous and worthy of their own blog post. But, I have noticed two significant problems with the way that SCM is currently being used on many of our projects:
- ChangeSets are frequently too large
- ChangeSets often contain code that shouldn't be committed
ChangeSets Are Too Large
I am frequently guilty of working for days on a particular task without committing any changes to source control. I like to wait until my task is completed. I don't want to break the build, and I don't want to commit broken code that might impede others. But, the biggest reason that I avoid committing my working code is that I don't want anyone to see it until I'm finished.
There are several problems with monolithic commits, including:
- Integration headaches: large ChangeSets increase the odds that changes will conflict with someone else's changes
- Useless file history: comments on large ChangeSets are, of necessity, more vague and less likely to convey useful information
Branch per Task
Every development task is a new, independent branch. Tasks are merged into the permanent main branch as they are completed.
(from Coding Horror)
Each time I am ready to begin a new task I create a branch for all work on that task. I generally have several active working branches that I can easily switch between. I check in code often to my working branch, rarely going more than a few hours between commits. Once I have finished working on a particular task, I merge my completed code back into the shared master branch. I am able to make frequent commits without breaking the master branch due to incomplete code.
Unfortunately, TFS does not easily support this style of development. Creating branches is inconvenient, and merging code between branches is torture. Although I would love to recommend that SRS adopt the style of development that I've described, I just don't believe that it is feasible with current versions of TFS. Given the painful nature of branching and merging in TFS, I don't see a better alternative to our current branch per-release strategy.
Given that TFS doesn't provide easy branching and merging, here's what we can do to find a happy medium. We should not check in broken code, but we shouldn't hesitate to check in code that is incomplete. Especially for new functionality, there shouldn't be any problem checking in a stub method that doesn't do anything. There are very few, if any, situations where we would be unable to commit our working code to TFS once a day.
There will no doubt be times where checking in small, granular ChangeSets will not be practical. There will be times when some of our tasks require us to break the application (not the build though!) in order to complete a task. However, it is my belief that with a little planning these times should be brief and infrequent.
It would be foolhardy to ignore the problems that accompany frequent check-ins. As the number of developers working in the same code base increases, so too does the probability that someone will check in something that will disrupt everyone else's work. This leads directly into my second topic: We must be aware of the code that we are checking in.
ChangeSets Contain Code They Shouldn't
When it is time to commit code to TFS, it is not uncommon for developers to simply check every file listed in VisualStudio's "Pending Changes" window and commit all outstanding changes. Although VisualStudio makes it incredibly easy to follow this bad practice (Why are all modified files checked by default?!?), we need to stop doing it. Sometimes debug code is committed and leads to problems that are only discovered after our customers have the release. Sometimes builds are broken as csproj and sln files are inadvertently modified. Sometimes it simply messes up the file's history (TFS always increments the version and updates the file's history, regardless of whether anything in the file has changed). These things should not happen. When checking code into SCM it is the developer's responsibility to verify every change that is being made. The developer should diff all changed files and verify every change that will be committed.
If anyone has found and enabled the option in VisualStudio to "Check in everything when closing a solution or project," please disable it immediately. No good can come from that option!
In some cases you may imagine that these procedures don't apply to you because you are the only developer on your team. That is a false assumption. Code should always be written for the long-term. Code should always be written and commented in such a way that another developer can pick up your tasks at any time. Julian Bucknall, the CTO of Developer Express, recently posted a thought to his blog that precisely expresses the point I am trying to make: Assume your code will be public. I am as guilty as anyone — probably more so, actually — of some of the bad practices that Mr. Bucknall describes. Edge Legacy is full of funny names and informal comments that I wrote to amuse myself. As we consider publishing more of our APIs for external consumption, it is increasingly important that the code we write properly represents the professional nature of SRS and increases the trust that our customers have in us.
I used Lingo for a few years without any problem. I never had any reason to contact their customer support until deciding to cancel my account.
Canceling my Lingo account was an absolute nightmare. In the end I spent nearly three hours on the phone before I was finally able to speak to someone who would process the cancellation.
I never spoke to anyone in their Cancellation Department. Honestly, I'm not sure that that department has any employees. In the end it came down to a war of attrition. I had to wait on hold and complain vigorously enough that they finally decided I was serious about wanting to close the account.
Many companies understand that when a customer calls to cancel, they have an opportunity to save that account. After this dreadful experience not only will I refuse to do business with Lingo again, I'll tell everyone I can to avoid them like the plague.
Below is the log that I kept while trying to cancel my account. I've done a little grammatical cleanup from the notes I originally posted during the phone calls.
Several weeks ago I made the decision to close my voip account with Lingo in favor of just using my cell phone. I got a new cell phone for my house and transferred my phone number from Lingo to my cell provider. Now I'm trying to cancel my Lingo service... what a joke. As I started writing this I'd been on hold for exactly one hour.
Friday, December 17th:
- 11:30am - I first called Lingo. I listen to the recorded message and navigate their menu system to talk to Customer Service.
- 11:46am - I waited on hold for 16 minutes before talking to a guy who took my account information and put me back on hold.
- 11:47a - He's going to transfer me to the cancellation department.
- 11:52a - The guy asked for a callback number. The cancellation department is too busy to take my call. From the way that he is talking about it it sounds like the cancellation department is one person who is out to lunch. He said that someone would try to call me back in the next 48 hours. I told him that this was unacceptable because I don't want to continue paying for service that I'm not using. He's going to try again so I go back on hold.
- 12:02p - He still can't transfer me because no one is available to take the call. I ask to speak to a manager and am placed back on hold.
- 12:03p - The manager is too busy to speak to me. I tell guy that I'll hold for the manager.
- 12:06p - I finally get to speak to a supervisor. I express frustration about this situation and ask what she can do to help. She is very nice but absolutely no help at all. She says that there is nothing she can do except continue trying to transfer my call. Because I have no other options, I agree.
- 12:37p - I've been on this call for over an hour now and am still on hold. I should have used a landline for this call. This is chewing through my cell minutes.
- 12:50p - Lingo wins this round. It's easy for me to sit on hold while I'm working at my desk but I have to go to a meeting. I am extremely frustrated!
December 22nd: my second attempt
- 9:09am - Called Lingo back. Went through their menu system and am on hold again.
- 9:20a - got a recorded message saying that they are too busy to take my call and asking me to please call back during normal business hours. According to their website, they've been open for over two hours already today (Mon - Fri: 9AM - 9PM EST)... this is normal business hours!
- 9:21a - I call back and am again placed on hold.
- 9:33a - I got the recorded message again and was disconnected. I called back immediately. I really wish that their hold music had more than just one song being played over and over and over...
Gotta love their "Terms and Conditions":
Cancellations will only be accepted via phone through Lingo’s Account Management Department at the toll-free number listed on the first page of your invoice, and will be effective upon the date that you cancel with a Lingo Account Management Representative. You will be given a cancellation confirmation number by the representative. Service cancellation requests by mail, e-mail, fax, equipment return, or any other form of non-telephonic communication requests will not be accepted.
We only accept cancellations by phone. Also, we don't answer calls to that phone.
- 9:44a - Disconnected again. Called back again. I guess that their system is programmed to hang up on me every 11 minutes.
- 9:55a - Disconnected again. Called back again. I guess that it's more likely that the system hangs up on me after being on hold for 10 minutes. The extra minute is probably just the time it takes me to call and get back in the queue.
- 10:06a - Disconnected again. Called back again. At least I was smart enough to route the calls through Google Voice this time so I'm not using my cell's minutes.
- 10:17a - Disconnected again. Calling back again. I think I'll try connecting to the billing department again (that's who I spoke with last Friday). They still put me on hold for the Cancellations Department but at least I didn't have to keep calling back.
- 10:26a - Spoke to a Customer Support Representative. She verified my information and then put me back on hold. She gave me instructions on how to call back "just in case we're disconnected." What a joke.
- 10:32a - a manager is on the line. She said that since I've been on hold for so long and since I had spoken to a manager on Friday that she would cancel the account for me. On Friday I was told that the manager I spoke with didn't have the authority to cancel an account. I don't understand her logic for finally accepting the cancellation but I really don't care. Just close this account! I asked her for a confirmation number and was put back on hold while she processes the cancellation.
- 10:36a - The manager processed the account and I have just sent me an email with the cancellation confirmation. This process has been an absolute joke!
The moral of this story: Don't signup for service with Lingo. It's not worth it.
Installing the RMagick gem can be a huge headache. Reading the HOWTO on the RMagick site is enough to make anyone nervous. Thankfully the process is much easier on ubuntu however; you only need three commands.
DISCLAIMER: I've only tested this on Ubuntu 9.04 (Jaunty) server.
$ sudo aptitude install -y imagemagick $ sudo aptitude install -y libmagick9-dev $ sudo gem install rmagick
And you're done! You can verify the installation using this irb command, taken from the RMagick HOWTO:
$ sudo irb -rubygems -r RMagick irb(main):001:0> puts Magick::Long_version This is RMagick 2.10.0 ($Date: 2009/06/19 22:07:05 $) Copyright (C) 2009 by Timothy P. Hunter Built with ImageMagick 6.4.5 2009-06-04 Q16 OpenMP http://www.imagemagick.org Built for ruby 1.8.7 Web page: http://rmagick.rubyforge.org Email: email@example.com => nil
Last night I was working on a new ubuntu 9.04 server on ec2 (it was ami-0d729464 from http://alestic.com if you're interested). Installing git via aptitude would have given me an older version so here's what I did.
$ sudo apt-get build-dep git-core git-doc libssl-dev $ wget http://kernel.org/pub/software/scm/git/git-220.127.116.11.tar.gz $ tar -xzf git-18.104.22.168.tar.gz $ cd git-22.214.171.124/ $ ./configure $ make all doc $ sudo make install install-doc $ git --version git version 126.96.36.199