Dealing with Asshole Customers

I’ve always taken great pains to be exceedingly fair, responsive, and back-bending in the way I interact with my customers. I firmly believe it’s best for business long-term if you always give your customer the benefit of the doubt and treat them as you’d want to be treated.

But recently, for reasons I don’t understand, I’ve been getting email after email from customers who are, quite frankly, being assholes to me from the very first contact. This type of customer has always existed, but in recent months the frequency that someone is a jerk to me before I even have a chance to respond has increased.

Lately, the customer starts out their email calling me names and cursing because “how dare I” release a new version of VirtualHostX a month or two (or three) after they purchased their copy. They believe that I’m somehow trying to screw them over personally by releasing a new version – something I do with regularity every 12 to 18 months.

I’ve always had a consistent, unwritten policy that any customer who buys one of my apps prior to a major upgrade gets a free upgrade to the new version. In fact, the same goes for any customer who emails in and complains no matter how long ago they originally purchased. I’d rather lose an upgrade sale and have a happy customer then make a few bucks and have them feel swindled.

In recent weeks though, I’ve had a change of heart. Chalk it up to one too many asshole customers I guess. I’m still happily providing upgrades to any one who asks. But for those who are jerks about it from the get-go, I’m instead cheerily refunding their money, deactivating their license, and nicely explaining that I’m not interested in their business.

It may be slightly passive-aggressive, but this new policy sure feels better. It’s nice to not get walked all over for a change.

One thing I am going to change to try and improve the situation is add a more prominent note on my product pages explaining the upgrade policy for recent purchases. Perhaps making the policy more clear will help prevent angry emails before they’re written.

Any other developers out there with similar policies? Would you react the same or handle the situation differently? I’d love to hear your feedback either in the comments or over email.

My Favorite Chair

I’m a bit of a snob. I don’t just like nice things, I like the best things. That’s not to say I spend extravagantly or throw my money around, it’s just that when presented with buying a good product or saving my money a little longer and buying a better constructed, great product, I’ll usually pick the great product. It’s why I bought an iPad rather than a Kindle Fire, it’s why I shop at Seven rather than Gap, and it’s why I use proper noise-canceling headphones rather than Apple earbuds. My point is that I generally take my time to suss out and spend my money on quality products that last.

So, four years ago, when it came time to buy a new office chair, I knew I had to do my research. I spend eight to sixteen hours a day in front of my Mac and my body starts to ache near the end no matter how many breaks I take. Over the years I’ve used everything from an art stool, to a $150 Office Depot chair, to whatever IKEA happened to be selling that month. I even picked up a $600 task chair from Relax The Back. They were all crap. The back support was non-existent. The seat cushion grew flat over time. And, in almost every case, the chair would wobble and lose height throughout the day. I knew there had to be something better available.

Honestly, I’m writing this review four years too late. Back in the Summer of 2010, while I was working full-time from home, I really did my research. I read countless reviews, inspected warranties, participated in online groups, and bought and returned a few models. The one chair that kept getting the highest marks, and, coincidentally, the only one I could never find in a store to try sitting in, was Herman Miller’s Embody series.

They don’t come cheap, running anywhere from $1,100 to $1,600 depending on the model, but after much back and forth, I finally placed an order for one sight-unseen.

I couldn’t be happier.

It has by far the best back support of any chair I’ve used. The back of the chair extends up to shoulder height and is modeled after the human spine. You can lean back into it and the material will move and bend with you as your turn or arch your back. The arms are made of squishy plastic that support your elbows without digging in. The seat cushion and the back are made of a mesh material that breathes and stays cool even after hours of use. And, best of all, the base is extremely sturdy. It doesn’t wobble. And it doesn’t lose height after extended use.

My only complaint is that it’s very noisy. Nearly every movement of your body causes some piece of the chair to groan. I’ve never for a moment thought the chair was falling apart or anything – nothing feels cheaply made – it’s just a side effect of how the base and back are constructed. They simply make noise as you move. It’s annoying at first, but not a deal breaker.

The chair also comes with a twelve year warranty. In the past I’ve had to replace cheap office store chairs every eighteen months or so. At $200 a pop, the Embody’s $1,100 up front price tag isn’t too far out of line if it lasts the full 10+ years.

Anyway, I’ve been using the chair in my home office for going on four years now and love it. So much so, that I bought a second one I bring with me any time I get an office job.

Money well spent.

Importing Jekyll Posts into WordPress

Nearly four years ago I switched my main site over to Jekyll. It’s been great. But late last year I decided to make that site and its blog purely about my software business and move all of my non-work posts over to my tyler.io domain so I could have a personal site again. To encourage myself to write more, I built the site with WordPress so it would be easy to publish. That meant I needed a way to convert and import all of my old Jekyll Markdown posts into WordPress. I found a few scripts that exported WordPress into Jekyll, but not the other way around. So I hacked together my own script, which I’ve pasted below. Hopefully this will help anyone wanting to make the same transition.

The script takes a directory of Markdown posts in the following format, reads their header meta-data, and imports them into your WordPress database.

date: 2013-04-08 20:57:14
title: PebbleCam
layout: post
permalink: /blog/2013/04/pebblecam/index.html
slug: pebblecam
Post content...

Switching from GitHub to GitLab

I’ve been a happy paying customer of GitHub since early 2009. But yesterday, for a few different reasons, I deleted all of my private repositories and moved them over to a self-hosted installation of GitLab. I didn’t make that decision lightly, as I’ve been very happy with GitHub for the last five years, but here’s why…

First, I’ve started working on a new Mac app. Every time I start a new project, unless it’s open source, I create a new private repo for it on GitHub. This project happened to be my 21st private repository on GitHub. If you’re familiar with their pricing structure, you’ll know they charge based on how many private projects you have. $22 a month will get you twenty repos. But as soon as you create that twenty-first one, you graduate onto the $50 a month plan. Maybe if I were actually hosting 50 repositories with GitHub I’d be willing to pay that much, but for the foreseeable future I’m going to be in the low twenties, and $50 a month is just too much. It’s a shame they don’t just outright charge you a dollar per month per project.

The second reason is an issue I’ve been mulling over for quite a while. I love the cloud. I love having my data in the cloud. But some of it is so precious, in this case my code, that I want to know exactly how it’s being taken care of and looked after. While I have no reason to doubt GitHub has plenty of backups in place, I have no way of really knowing for sure how safe my code is. Hosting it myself has its inherit risks, too, but at least I can have full ownership of my data and be certain of the backup strategies in place. This also dovetails nicely with the pleasure nerds like myself get in doing a job themselves. Whether that’s hosting your own email (which I’m not crazy enough to do), managing your own web server (yes, please), or automating your own digital backups, there’s a sick pleasure to be had in doing a job yourself and doing it well.

A final reason for switching away from GitHub was the uneasy feeling I got watching the story of Julie Ann Horvath unfold last week. I didn’t like the idea of my money going to a company that seemed so fundamentally broken. Since then, GitHub has taken forceful, actionable steps to correct the issue, but it still worried me.

So those are my three and a half reasons for moving my private repos away from GitHub. If you agree with me, or if you have your own reasons for wanting to move away, what follows is a brain dump of the steps I took towards getting moved over and situated happily on a GitLab installation.

First off, if you’ve never heard of GitLab, go take a look through their website. It’s a Rails app that is shamefully funny in how closely they’ve copied the look and feel and functionality of GitHub. Everything from the activity timeline, to pull requests, to user and team access roles, to issue tracking, to shareable git-backed gists. It’s all very nicely implemented. Many open source projects start off strong and can later falter when the creators get bored. But I feel fairly confident in GitLab as their community open source version is based off an enterprise product they sell and do support for. Quite a few businesses are using GitLab as a GitHub replacement in situations where their code needs to remain on site.

So, where are we going to host it? My initial thought was to boot up a new virtual server with Rackspace, which is where I host all of my business servers. Rackspace is great. A little expensive, but the customer support makes up for it. Their minimum monthly price for a 512mb server, which is all we’ll need, is around $10 a month. I was nearly about to create the server when I decided to finally take a look at DigitalOcean. They’re the new hotness in cloud hosting and have a reputation for being extremely inexpensive. (Bonus points: they offer two-factor authentication on their user accounts, which is something Rackspace still lacks.) Poking around, I found I could get a comparable 512mb server with DigitalOcean for a flat $5 a month. But what really sealed the deal is they offer one-click installs of various server apps – WordPress, etc. I wasn’t looking forward to the fairly intensive setup that GitLab requires, but amazingly, GitLab is one of DigitalOcean’s one-click installs.

True to their word, I had a ready-to-go GitLab server up and running in less than a minute after clicking the “create” button. All that remained was fine tuning everything to my needs.

The first step upon getting a new cloud server is to secure it. I always follow the steps outlined in this guide. It does a good job of locking everything down and only takes about five minutes to follow.

Of note, when you get to the section about enabling ufw (the firewall), DigitalOcean boxes don’t come with everything you need installed. I had to run the following command before setting up ufw…

sudo apt-get install linux-image-$(uname -r)

Another note, and this is just personal preference, I also modify my ssh port to be something non-standard. That can be changed in…

/etc/ssh/sshd_config

Also, while the user facing side of GitLab is great, I have no idea how security conscious they are. I’d hate for an unpatched security hole in their web app to expose any of my private code. One way to mitigate that chance is to lock down web traffic to the specific IP addresses you’ll be accessing it from. Your home, your office, etc. With ufw it’s just a quick…

sudo ufw allow from your-ip-address to any port 80

for each of your IPs.

Once you’ve gotten the security taken care of, you can move on to configuring GitLab. Most of the hard work is already done for you by DigitalOcean. You’ll just need to fill in the appropriate values in…

/home/git/gitlab-shell/config.yml

and

/home/git/gitlab/config/gitlab.yml

Then restart GitLab with…

sudo service gitlab restart

With all that done, the next step is moving your repositories from GitHub to GitLab. (I’m sure there is a better direct git-to-git way of doing what follows, but this was the simplest solution for my needs.) For each of your repos, do a clean mirror to your Desktop to make sure you’ve got everything.

git clone --mirror [email protected]:username/repo-name.git

Then, cd into the repo directory and….

git remote add gitlab ssh://[email protected]:22/username/repo.git
git push -f --tags gitlab refs/heads/*:refs/heads/*

That final git push with all the refs will push every branch and all of your tags making sure nothing is left behind.

Once done, you can safely delete your repo from GitHub.

The last step is making sure you have rolling backups of your GitLab installation and repositories in place. I looked into piecing together my own backup script until I realized GitLab already has a rake backup task available that stores everything into a single tar file. Perfect. I can then just upload that to S3 for safe keeping. To do that, we’ll be using s3cmd to handle the uploads.

sudo apt-get install s3cmd

Configure it with…

s3cmd --configure

Then, create a script in your git user’s home directory called backup.sh containing…

cd /home/git/gitlab && PATH=/usr/local/bin:/usr/bin:/bin bundle exec rake gitlab:backup:create RAILS_ENV=production
s3cmd put tmp/backups/`ls tmp/backups/ | grep -i -E '\.tar

Setup cron to run that script once a day and you’re good.


 | tail -1` s3://bucket-name/git/

Setup cron to run that script once a day and you’re good.