April 29, 2009

Typing

When researching this article on google, I found that the subject of my post today is one that elicits angry, angry responses from people. And I know this to be true: I've experienced it first hand. I've often been a little puzzled at such reactions, but analysis of it isn't the subject of today's article: it's about keyboard layouts. So what can I say? Please don't take offence at my opinions about best practice in typing. Maybe just remember this article for when (if?) you develop symptoms of RSI.

Phew, with that out of the way, let me fill you in on my recent adventures in keyboard layouts. I'm a pretty damn good QWERTY typist, but I've also got really bad hands. I won't go on with medical lingo, but I'll say that I can't use laptop keyboards for very long, and even on my Kinesis kit (which is a life-saver), I've got to be careful to take breaks and so on, otherwise I find myself unable to type for a couple of days while my hands recover.

This shouldn't come as any surprise though, QWERTY is notoriously bad in terms of the amount of work the typist has to do. I won't go on with all the metrics people cite, because those are easy to find too.

So, every once in a while, I think to myself that it'd be great to learn an alternative layout. It seems like a solved problem, but it is a bit of a time investment, so it's not something I do flippantly, and I've been wrong about it before: some time ago, I taught myself the Dvorak layout. A lot of the criticism leveled at alternative keyboard layouts is that they take too long to learn. And maybe they do; that depends on your perspective. For me, I was able to type effectively on Dvorak after about 2 weeks. I still wasn't as fast as QWERTY (sorry, I don't have measurements to hand), but certainly fast enough to be productive at work.

But for me, it's not about speed. Dvorak held the promise of making my hands do less work, and that's a big deal to me: it means I can work longer: both as in more hours in the day, and also more years of my life. I used it for a little while, but eventually gave it away. The reason I couldn't keep using it is that while as a total my hands did less work, it placed more strain on my right hand than with QWERTY; in particular on the right pinky (which, after a terrible window-closing accident, is my weakest finger). And honestly, it was a real mental exercise to learn, which meant that I'd moved fatigue from my left hand to my right hand and brain. I viewed it as a net loss, so just ramped up the number of typing breaks I was taking a bit, and switched back to QWERTY.

That was a while ago now, but fairly recently I stumbled upon Colemak, which is a newer keyboard layout than QWERTY and Dvorak, and has a few properties that I find appealing. The key points are that they've made it easier to learn (far less mental fatigue when learning it), resolved the lopsidedness of Dvorak, including right-pinky-work, and it requires far less work to use in total than either QWERTY or Dvorak.

Sounds too good to be true!

So, I've been giving it a go. A lot of people have a lot of advice about the best way to learn a new keyboard layout. For me, my continued productivity is key to my survival, so I can't really afford to produce less stuff while I learn. For this reason, I've been typing QWERTY for most of my day, but once I get to a point where muscle fatigue means that I'd be slowing down, I switch my keyboard over to Colemak. It works pretty well for me: as things stand, I can't type as fast in Colemak, which means I just naturally type fewer keys per minute, but it's also very easy to see that your hands do way less work when using Colemak, so I almost equate it with a typing break. And little by little, I've been getting better at it.

So far, I've found it far less frustrating than Dvorak, and after the hectic finger-moshing that QWERTY requires, it's honestly a bit of a relief to get to my Colemak sessions in the afternoon. But, I'm not there yet, and it's going to take a bit of time with my chosen method of learning. But, in less than a week of 0.5-1 hour per day, I've started doing basic "chords". I thought it would be easier for me to learn, having learnt Dvorak, but interestingly it doesn't seem to be. My brain seems figure that if I'm not typing QWERTY, I must be typing Dvorak, so there's a few keys which I always seem to reach for the Dvorak location on. But, I'm getting better way faster than Dvorak.

So yeah, I can't claim that it's a perfect solution yet; I can't yet do a whole day's work in it to be able to compare. But, if you're finding that typing is becoming a chore, I recommend that you check it out.

While learning, I made this layout diagram, which I found useful:

Which is based on the one on the Colemak site. The dark blue keys are the ones that are shared with QWERTY, light blue are a handful of keys I kept finding I needed for various commands I use a lot (mostly for bash and vim), and the purple keys are the vowels. The red line in the middle is where the split between sides of the keyboard are on the Kinesis keyboard. They've also got different colour coded images on their site, but they're more targeted at people who can't touch-type in QWERTY.

Before I leave you, I'll make just one more point. Touch-typing, in whatever layout, is a good move. If you do a lot of typing, you've probably already developed most of the skills you need (you remember where all the keys are). Again, speed isn't my focus here; I just found that learning to touch-type meant that I could devote more of my mind to processing what was on the screen, which ultimately meant that I could get more done. Learning Colemak might be a good opportunity to reform.

Anyway, if you do try it, I'd be interested to hear your experiences. Happy typing!

March 9, 2009

Great Customer Support

Whoo. Been a while since I've written here. You know the drill, busy and all that, but there's just too many things I'll forget unless I write them down!

Customer support is a hugely important aspect of a successful business, especially a small business. In my previous job, well I wore more hats than there are names for, but one hat that got a lot of my attention was the "be nice to the customer" hat. In my new job as, well, entrepreneur, it's once again a big part of my work.

So I wanted to write a bit about the subject: why it's so important, how you can go wrong, and what I think constitutes exceptional customer support.

Let's start at the start: why? Well, it's pretty simple: Everyone has had a bad customer support experience. You know how it works: your widget starts making a crackling sound, you start to fear (perhaps irrationally) that it's developed a fault that could be dangerous to your children, so you call up the manufacturer. From there, a machine answers you, you have to listen ultra-carefully to what it's saying to know which number you need to dial to get to the next level of options which you need to listen ultra-carefully to. You get put on hold for 15 minutes, you eventually speak to a human who advises that you've been put through to the wrong area, and will gladly put you through to the right person, but you'll need to wait on hold again, so you do, and another 23 minutes passes and you talk to the "right" person, but they can't help you.

Arh!

Now think about what happens here: if you ever hear that a friend of yours needs to buy a widget, you're going to tell them "whatever you do, don't buy it from WidgoCorp. My Widget broke and those bastards made me wait on the phone for an hour before telling me that my widget was 2 days out of warranty!". You're probably a little angry at WidgoCorp, but mostly you want to make sure your friend doesn't suffer the same way; you're acting mostly out of compassion for your friend rather than malice toward WidgoCorp, but nonetheless, WidgoCorp just lost a sale.

Compare and contrast: About a year ago, I bought a Samsung LCD monitor. In general I'm thrilled with it, but about 3 months into its new life with me, it developed a fault and refused to turn on. As you can understand, I was disappointed, but it's technology: you expect and accept that these things will happen sometimes. So I called up Samsung support, and I was absolutely blown away: a human answered the phone after about 2 rings. Even more amazing, without needing to transfer me or put me on hold he told me that this was no problem, just read this number off the back of the thing and he'll ship me a replacement straight away; all I had to do was to put the broken monitor into the box and send it back to them. The guy was polite and well-spoken; I called up anxious and expecting a fight, and they were reassuring, calm and glad to have the opportunity to help me out of a jam.

Wow!

Now, the execution of that return wasn't flawless: it did mean I was without a monitor for a while, but I was able to cope with that (some people mightn't, but in fairness to Samsung, those people should probably be purchasing a "next day" support contract or something), but all that aside, on the basis of that call I felt like Samsung were doing everything they reasonably could to sort out my problem so I didn't call back and bother them about it, and since then I've recommended Samsung monitors to everyone who'll listen. I know that they've made at least one sale based on my recommendation of them. I'm pretty sure I've made more recommendations since that phone-call than I would have had the monitor never developed a fault!

You might argue that past a point, you don't really need to worry about support. To be fair, I've never been involved in the management of a large scale company, but my guess is that you really need to be really quite ginormous for this to be the case, and if you're that large these days, you're likely to be on the wrong-end of anti-competition legislation before too long. But even if you're in that happy situation, good support is cheap marketing. In my previous job, I'd overheard engineers recommending my employer's technology on the basis of how attentive we'd been to their concerns. As founder of an iphone-apps startup it's even more direct: people leave good feedback on the apps store when you do good support work, and that feedback is there for everyone to see, and the "star rating" they give you has a direct impact on the number of sales you make, so that good feedback turns into dollars very directly.

So that's why you need to do it: it'll make you money, plain and simple. The next part of the story is how well-meaning support can go bad. I'm going to give a handful of examples of companies I've personally dealt with, which I do not to try to shame these companies, but to give non-contrived examples.

So, first on my list: Lenovo. I own a Thinkpad x61, and honestly I quite like it; it really is an amazing piece of engineering. It has a tool that it ships with that applies updates to the system, you know: drivers, BIOS updates, updates to the updater application. Standard stuff. So on one occasion it told me it had a critical BIOS update that it wanted to apply. Fair enough I thought, I told it to go right ahead and do it. It failed. It didn't have a rollback process. I rebooted, and of course, the system was "bricked" (a technical term meaning that it is as useful as a brick; this is probably being a bit kind as I don't think I'd want to build a house out of defunct thinkpads) I threw my hands up in the air and thought "they seriously still can't get this right?", took a deep breath and called Lenovo tech support.

I got the automated menus treatment -- disappointing but expected -- I got put on hold -- again, disappointing but expected -- then I spoke to someone about the problem. Initial indications were good: he was polite, and quickly grasped the problem, but ooh boy, not at all nice about the situation. His perspective was that I'd clearly done something wrong in applying the update, that BIOS updates should never be applied unless explicitly instructed to do so by a Lenovo support technician, and that he'd help me out, but he was really going out of his way here, doing me a real favour.

Let me try, as dispassionately as possible, to deconstruct what was wrong with his response. First of all, he assumed that he knew more than me. I hold a computer science degree, had been working as a software engineer for, well, a long time, and at the time was working for a company developing products built around programmable logic devices. I've written kernel modules and have supplied bugfixes to device drivers. I would estimate that I probably understood the situation better than ~99% of the population. It's seriously infuriating when support techs do this to me. I can understand how support techs can get to this point, but you need to guard against it, and you need to make it part of your support mantra. Nothing good can come of this kind of condescension. Either you'll hit people like me, capable of building the damn software ourselves, or you'll hit people who are terrified by what's happening, and you're going to add to their level of frustration. No-one intentionally breaks their computer, and in this day and age, it should be really, really hard to break a computer unless you're trying. If it's possible for someone to break the thing in normal use, it's an engineering problem, and your company should treat it as such and take responsibility for fixing the problem (why? Because you'll save money on fielding those support questions, for one).

Secondly, he asserted that I should not have applied a BIOS update without explicit instructions to do so from support. That's a fine policy to have, but you can't also have "critical" BIOS updates that will install themselves unless the user explicitly says not to. The default behaviour can't be "brick the machine"! This isn't just a support problem -- it's a case of engineering not talking to the guys on the front line. That's something that gets harder as your company grows, but you'll build better products and spend less on support (which is an ongoing cost) if you can facilitate that kind of communication. Given my credentials above, trust me when I tell you that it is entirely possible to engineer a system that would not fail in this situation (BIOS updates are a bit hairy, say when there's power-loss, but this was a pretty simple case), or at least trust me when I tell you it's possible not to tag these updates as "critical".

Thirdly, he acted like he was doing me a favour. That's just wrong: if you're calling support, it's because of a failure in the company's technology; it might be a bug, it might be bad design, it might be bad marketing. But as a support-guy, you need to welcome the opportunity to fix the problem, not treat the customer like they're a nuisance and you're just doing your best to be a nice guy. The customer is doing you a favour by calling you rather than, say, writing letters to the editor, tweeting about your bad product, or (like I guess I am) blogging about your abysmal support. Since the customer is doing you a favour, do your best to make them feel like you really appreciate it.

My last gripe with Lenovo was that during various dialogues with them, they tried to pass the buck: Since Lenovo acquired the Thinkpad brand from IBM, there's a stack of opportunities for them to do this. Further, since they ship the machine with 3rd party software, they can point the finger at the software vendors too. It gets even better, if you speak to their hardware support group, they'll tell you that they can't help you because BIOS updates fall under the jurisdiction of the software support group. "Can I talk to software support?" "There's no support for software." There are cases where a third-party is legitimately to blame for the problem, but it doesn't suffice to identify this, you still need to solve the problem.

Let's move on. Telcos are next on my list. I won't name a particular one, because I've had bad experiences with all the carriers in Australia (except Three; I've never had a Three phone). I won't go into as much detail here, as I think you've got the flavour of this by now, but the problems include: confusing automated menu systems, many levels deep. Long hold times. Over-specialisation of staff (meaning that you'll need to be transferred way too often). Bad ETAs.

So alright, that's some of what can go wrong. Hopefully the rest of this will be briefer -- here's my list of what makes a great support experience. It's tailored to email support, since that's most of what I do, but I think a lot of it is applicable to phone support also.

  • Thank the user for getting in touch with you. Don't be disingenuous about this, and be concise. No-one calls wanting a love-in, but it's nice to know that the customer's support for your product is appreciated.
  • Apologise for the problem the user is experiencing. Again, don't drag this out, but this communicates that you (the company) is accepting responsibility for the problem, and wants to help.
  • Briefly explain the problem so that the user has some perspective. This serves two purposes: some people feel outraged about the problem and need some rationalisation to be able to let the dialogue progress. It also gets you some good-will, as it will give the user some appreciation for the scope of the problem you're solving here. Be careful not to make this sound like you're passing the buck, and make sure that you don't detract from your efforts to take responsibility for the problem.
  • Take responsibility for the problem, and for the solution. If you can, provide a fix or workaround immediately, if you can't, commit to a date for a fix and stick to it. Provide interim measures if you can. Do everything you can to help the customer as quickly as possible.
  • Be as honest as you can, because customers can tell when you're telling the truth and speaking sincerely. They'll respond in kind and again, you'll get some good will that you can trade against in future dealings with that customer.
  • Be polite and respectful. It doesn't cost a cent, and it will be remembered.
  • Escalate recurring problems to engineering so that their solution will be built into the next version and you won't need to worry about this issue ever again. Also get it across to marketing (or wherever) to get this stuff on the FAQ, blog, whatever. It'll save you and your customers time and frustration.

But most importantly of all, solve the problem! The thing that people will remember the most is how long it took them to get a satisfactory solution to their problem. That's all they want, so providing that is your number one priority. One last point I'll make here is that when evaluating that amount of time, time spent on hold gets magnified by about 1000 in the customer's mind, and it's really hard to earn enough good will to earn back 1000 minutes of time wasting. Call back services will make all the difference here.

So ok, here's an example of how I think your support responses should look:

Hi XXX (customer name),

Thanks for writing in. Sorry for the trouble you're having -- it's due to a bug in the email system we discovered late in the release cycle. There's a fix in version 2, a free upgrade due out in August, but in the interim, placing a hyphen before the server name should resolve the problem for you.

Please do get in touch if you hit any more problems.

Thanks for using YYY (the name of your product)!

Cheers,

James.

Of course, it won't always be that simple, but getting a response like that one out to every support request you get is a good goal to have.

That's it for now!

July 12, 2008

GasBag

One of the reasons I haven't had much time for writing here lately is that I've been working on starting a company. We're all perfectionists in this company, so there's still a bit more work to do before we actually make a release, but we've put out a video to let people know what's coming.

There's a high-quality version here on blip.tv, and there's a lower-quality (but more compatible, it seems) version here on youtube.

You can sign up to be informed of updates over at our website.

May 8, 2008

OCRopus (tm) Packages for Ubuntu Hardy

This is a poor substitute for an entry, I realise, but I've just made packages of Google's OCRopus(tm) project for Ubuntu Hardy Heron. You can grab it here. No support for apt-get/aptitude, as I'm sure it will be in Hardy+1 and don't want to dilute your /etc/apt/sources.list file with entries that will rapidly become stale. Also, it's unsigned. Sorry. The md5sum of the file is 9aee9459a6dc120a5a5537b49a67db0e if you want to verify it. It has a handful of dependencies that are all in the main distribution, so you should be able to sort those out in short order.

So, why? Well, the broad problem I'm currently trying to solve is to eliminate the massive pile of paper that has been growing over the course of years in my house. See, there was a time when I just threw out any piece of paper that came my way, with no regard for whether I'd need it again in the future. It was a care-free and happy time, and one that I shall fondly remember for the rest of my days. Then, something terrible happened: I started earning enough money that I had to file tax returns. The first few of those were painful, mostly because I had none of the bits of paper that I needed in order to handle the onslaught of uninteresting questions posed by the ATO's various forms.

So these days, I don't throw any piece of paper out, because I'm not suitably familiar with tax that I can confidently decide whether I'll need it or not in the future. That's not entirely true; it's not just the tax office that ask me to retrieve pieces of paper that I take no personal interest in; I've had cause to retrieve all manner of documents containing information that initially looked pretty ephemeral to me.

So this has come to a point where there's this whole shelf of my book-case devoted to pieces of paper that I have no personal interest in, but at one time in my life I thought might be valuable. Once any problem reaches the size of a bookshelf, it's a problem large enough that I think a computer would be a helpful tool to solve it.

My solution is one that I thought would be pretty standard: buy a sheet-feeding scanner, shove the documents into said scanner, scan them and throw away the originals. But of course, that's not actually enough; for this to actually solve the problem, I need to be able to locate any of these documents relatively trivially; I want to be able to search through them similarly to how I search my email: by full text search, tagging, date ranges etc.

Anyway, this last part requires me to find a way to extract the text from my scanned documents for indexing and searching. That means OCR. Anyway, I'll spare you the details, but everything I tried was, well, appalling. Embarassingly bad. Seriously. My test image was a pretty clean scan of a white page with plain black sans-serif text on it, and I had one app generate a page of punctuation as its output!

The bottom line is that OCRopus was far and away the best of the tools available, and since I'm anal about software installation I packaged it. I hope it's useful to you.

The other part of this story is that I also bought a scanner as part of this project. It's the first one I've ever owned. It turns out that these days you don't just buy scanners, you get a printer and fax machine and photo-copier too! The device I bought was the HP OfficeJet 6310 All-in-One, and it's awesome. I won't go on too much about what's so great about it, except to say that if you run Linux, install hplip and you'll have it working in seconds. It has an ethernet port on it, so you just plug it straight into your network and everyone can use it straight away.

But it gets better, you don't actually have to install any software at all! You can just punch in its IP address in a web-browser, and it has a web-GUI thing that will let you scan documents without using any client-side software at all! Neato! And for ~$150, you can't go wrong.

Hopefully I'll be back with something more substantial to say soon. Thanks for your patience throughout my hiatus.

November 23, 2007

Buying a Laptop

I've been trying to buy a new laptop recently, a project which I have not yet succeeded in. However, I've learnt a few things about buying a laptop that I thought might be worth sharing.

Buy it from America

Laptops are seriously half-price if you can get them anywhere that's not Australia. But the US is an especially good place to buy because of the Aussie dollar's relative strength. I don't know why, but laptops cost approximately half as much. Don't believe me? Compare US Lenovo's Thinkpad price and Australian Lenovo's Thinkpad X61 price. At the time of writing, the base-model X61 is $AU2199 or $US1025 (about $AU1,175.73. There'll be some tax too, but it's not going to be $1000). Insanity!

Get an American Express card

After having decided on a TP x61, I went through Lenovo's ordering page and got all the way to the end and discovered that it wouldn't let me use my Australian credit card -- the billing address doesn't let you specify a country, and all the states it lists are American states. However, if you read their unlinkable FAQ (you get to it by going through the ordering process, getting to entering your billing address and clicking the "credit card profile" link), it says:

If the billing information provided does not match what is on file with the credit card provider then your order will be held until we can verify that you are the authorized card user.

...

International credit cards
An international credit card is a credit card issued outside of the United States with a primary billing address in another country. To place an order using an international American Express card please call 1-866- 96-THINK. American Express is the only international credit card currently accepted by Lenovo.

I don't actually know if American Express have a special "international" card or not, but it seems like Amex is the card to have if you want to buy stuff from the US.

The closest thing to a redbook.com.au equivalent

redbook is a site listing all the cars, ever, along with detailed specifications and expected pricing and so on. It's immensely useful for buying a used car, or even a new one. Unfortunately I haven't found an equivalent for laptops, but at some point I did stumble upon CompUSA's laptop page which has a fairly representative set of current computers and a highly usable interface for narrowing down available options based on your requirements. I'd recommend buying direct from the laptop's manufacturer over buying from CompUSA, but they do have a very useful webpage.

Use discount coupons

It turns out, that like every other strange, perverted practice imaginable, there is an internet community committed to collecting and publicising the details of discount coupons for various laptop manufacturers. The one I stumbled onto was Fat Wallet. As an example, they have this page detailing discount codes for Lenovo laptops, including a coupon for a further 20% off!

Buy it at Thanksgiving

I haven't quite broken the code of when thanksgiving is, or what it is, but it seems to be a period of the year where no-one in America makes any money. It seems to be around November (ie: now). Whatever it is, it's a time of year when there's all kinds of discount offers to be had. Take advantage of it. See also bfads.

Get a "business" model

The "business" models from most vendors are typically much better machines, but that's not the reason I give this piece of advice. The reason is that since you're buying the machine from outside your home country, you'll want an international warranty; an extravagant extra normally only afforded to the "business" models (though exceptions exist).

Get it on Salary Sacrifice

I don't have a reference for it handy, but if utter the words "Salary Sacrifice" to whoever does payroll at your employer, you'll get the machine on pre-income-tax money. Which is great.

Can you Depreciate a Salary Sacrificed Laptop?

I don't know. I struggled with this on my last tax return. The argument for is that no matter what it cost you to acquire, you start out with an asset worth X, and it will lose a percentage of that value each year. So you should depreciate it. The argument against is that you didn't pay income tax when you bought it, so there's no income tax to claim. I don't know what the answer is, but I will point out that the tax pack lists a laptop computer as one of their examples in this section, and they're generally pretty careful about noting exceptions such as this. Make your own decision, but it's worth noting that there's a fairly defensible case either way.

Don't have time to get an Amex?

This is the unfortunate situation I'm in, and it renders most of my previous advice moot. However, you're not completely lost; it turns out that there are some vendors who sell laptops on ebay, and will accept paypal payment. They'll deliver it to anywhere in the US, and some of them will deliver internationally as well. If you can pick it up in the US, that's preferable, as you won't have to pay customs on it.

That's it for now. I'll be sure to let you know if I learn anything else before the conclusion of my laptop odyssey.

November 8, 2007

PCC Package for Ubuntu Gutsy

There was a bit of a stir not so long back about PCC (or more informative wikipedia page) being imported into OpenBSD. For reasons I hope to elucidate upon in a follow-up to this article, I was interested in giving PCC a try, but there were no packages for my OS of choice: Ubuntu.

So tonight, I built such a package. You can get it here, possibly for a limited time only. It's pretty basic, I've just used the extremely handy dh-make and forward-ported the patches from the FC7 package.

So far I've confirmed that it can compile "Hello, World". Hopefully I'll get it to do something a little more useful soon. In the interim, enjoy!

October 15, 2007

E: Dynamic MMap ran out of room

The solution to this one always seems to be harder to find than I remember, so I'm writing it down here. The problem is that you add some sources to apt, and then you do an update, and apt helpfully reports

E: Dynamic MMap ran out of room

As far as I can tell, it's complaining because it has tried to use my favourite syscall (no, really, it's awesome), mmap to load its dependency database into memory lazily, and a sanity limit has been reached.

The solution, on Ubuntu, is to put the following into a file called /etc/apt/apt.conf.d/00local (previously I've used /etc/apt/preferences; Ubuntu seems to adopt a more structured configuration system):

APT::Cache-Limit 50000000;

And generally you want that number to be something smaller than the amount of memory you have available on the system, though I suspect in practice it rarely matters (the kernel will over-commit on memory, but it's only a problem if your request touches more memory than you have; single package installation should thus be fine, dist-upgrades probably won't be. Note: haven't tested that theory).

This, incidentally, is an example of a bad error message. It's not appalling; the message does uniquely identify a particular fault, and as such you can find what you need with a minimum of googling. But it could be a lot better: in this case the application could have known what limit to use, and could have informed you that it's doing this for your own safety (the limit will be in place to prevent swapping), and could have even told you how to disable this behaviour (as above). More puzzling to me is why it doesn't do this dynamically based on the amount of physical memory available; it could even adopt a different algorithm when it detects low-memory conditions.

But anyway, there's the solution. I hope that you never have to go looking for it, but there it is nonetheless.

October 6, 2007

Reading and Writing Image Files with imlib

I thought it had been a bit too long since we'd had an entry on codelore about code. So, here it is. A while ago, I was trying to write some code to do some image processing. The first step, to read in an image file, proved to be immensely, horribly, painfully difficult. There's a bunch of libraries around, but the problem of "please give me a 2D array of pixels" is somehow not a use-case they anticipated.

I don't quite know how this dire situation came about, and I'm not that interested (though I expect one could learn a lot from API design by doing that research). Instead I just wanted to share my solution to this problem in case someone else wants to be able to read and write image files.

The solution that I found is a library called imlib (sources here). Now, it's not perfect; notably it's thread-unsafe by really quite extensive design (why?!), but it does have a simple way to load images of pretty much any interesting type, and it has methods to get pixels and draw lines (which I will use as a poor but workable substitute for having a pixel setting method). I won't talk too much more about it, I really just wanted this to get out there so that the next person to search for "reading and writing images 2d array" will not be as disappointed as I was. Note also that the industry-standard ImageMagick comes pretty close to this level of simplicity, and if you're working in C++, the Magick++ interface actually looks pretty nifty. What follows is the simplest thing I could get to work in C.

/**
 * Image loading and saving example code. This code is free for any purpose;
 * knock yourself out. No warranties expressed or implied. Build this example
 * program with a Makefile like this:
 * 
 *  img: main.c
 *      gcc `imlib2-config --cflags` `imlib2-config --libs` -o img main.c
 * 
 * Author: James Gregory <codelore@james.id.au>
 */

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <libgen.h>

#include <Imlib2.h>

#define pixelVal double

struct matrix
{
int width, height;
pixelVal **vals;
};

struct image
{
int width, height;

struct matrix *red;
struct matrix *green;
struct matrix *blue;
};

struct matrix *newMatrix(int width, int height)
{
int i;
struct matrix *mat = (struct matrix *)calloc(1, sizeof(struct matrix));

mat->vals = (pixelVal **)calloc(width, sizeof(pixelVal *));
mat->width = width;
mat->height = height;

for(i = 0; i < width; i++)
{
mat->vals[i] = (pixelVal*)calloc(height, sizeof(pixelVal));
}
return mat;
}

struct image *loadImage(const char *filename)
{
Imlib_Image img;
int i, j, width, height;

struct image *result = (struct image*)calloc(1, sizeof(struct image));

img = imlib_load_image(filename);
imlib_context_set_image(img);

width = imlib_image_get_width();
height = imlib_image_get_height();

result->width = width;
result->height = height;

result->red = newMatrix(width, height);
result->green = newMatrix(width, height);
result->blue = newMatrix(width, height);

for(i = 0; i < width; i++)
{
for(j = 0; j < height; j++)
{
Imlib_Color col;
imlib_image_query_pixel(i, j, &col);

result->red->vals[i][j] = (pixelVal)col.red;
result->green->vals[i][j] = (pixelVal)col.green;
result->blue->vals[i][j] = (pixelVal)col.blue;
}
}

return result;
}

void saveImage(struct image *img, const char *filename)
{
Imlib_Image out;
int i, j;

out = imlib_create_image(img->width, img->height);
imlib_context_set_image(out);

for(i = 0; i < img->width; i++)
{
for(j = 0; j < img->height; j++)
{
int red = (int)img->red->vals[i][j];
int green = (int)img->green->vals[i][j];
int blue = (int)img->blue->vals[i][j];

red = red <= 255 ? red : 255;
green = green <= 255 ? green : 255;
blue = blue <= 255 ? blue : 255;

imlib_context_set_color(red, green, blue, 255);
imlib_image_draw_line(i, j, i, j, 0);
}
}

imlib_save_image(filename);
}

int main(int argc, char *argv[])
{
struct image *img;

if(argc != 3)
{
fprintf(stderr, "Usage: %s <input file> <output file>\n", basename(argv[0]));
exit(-1);
}

img = loadImage(argv[1]);
saveImage(img, argv[2]);
}


(apologies for the awful code listing. Anyone with killer ideas for posting code on Movable Type blogs, let me know)

That should build a little program to convert an image file between image formats extremely slowly; something every programmer should have in their arsenal.

Now, some of you might be asking why I chose to split the red, green and blue channels into separate matrices. An excellent question. The reason is that the particular application I was working on had the luxury of being able to treat each channel separately, so from a code clarity perspective it made sense: I wrote my function to process one channel and then a wrapper to call it three times, but perhaps more interestingly it also gave me a speed advantage: it meant that I was able to fit a much larger portion of the working set into L2 cache. Unfortunately in the example above where you read and then immediately write the file you get almost the worst possible memory access pattern. If you are in the business of writing programs to do that, let me give you some advice: Stop. It's already been done.

Anyway, I hope that proves useful to someone. Feel free to use it however you wish.

August 25, 2007

More CV Advice

Mary just read my previous piece CV Advice and mailed me with this question:

why not just advise people with a non-Anglo surname to list their visa status? Is there some reason why "Mohammed al-Rashid, 42 Waratah Way, Sydney" is more reassuring that "Mohammed al-Rashid, present location: Sydney, visa status: Australian citizen"?

I must confess that that particular piece of advice didn't come from my own reading of CVs; I make a point of leaving aside such considerations of "are they legally allowed to work for me?" until my second pass, because I realise that it can be a somewhat difficult question. No, that piece of advice came from watching more than one of my superiors over the years discard CVs after reading only the name of the applicant. I've been shocked and appalled at this practice, but as an author of a CV, you can't lecture the reader on their unreasonable prejudices unless you get the interview, so you deal with that problem first.

To address the first part of the question -- why not just list your visa status -- don't get me wrong; if it's relevant, you must list your visa status. But that's trying to achieve a separate goal -- in stage two when the reader is considering interviewing you, they'll need to work out the implications of your visa status and make sure you'll actually be able to work under the necessary conditions.

But listing your address is about beating the possible prejudices of your reader, who will no doubt have reviewed a significant minority of CVs from people outside the country, who claim to be able to work in Australia immediately, only to discover after some closer inspection that actually they're eligible for a visa, haven't got it yet, and will need 3 months to relocate before being able to start in your organisation. I know I've read CVs like that. I understand what might motivate someone to do that in a CV, but the bottom line is that I need someone now, and as the author of your CV you have 30 seconds to make sure that your honesty in the matter of your visa status and availability is understood and appreciated. You need to give your reader all the help that you can.

Just to clarify, I think everyone should put their whole address in, because it adds to your credibility no matter what your name is. But, if your name "sounds foreign" (I'll leave it to you to decide if your name does), the benefit is multiplied because there's a possible fear, which might not be justified, but is probably with precedent, that they'll be wasting their time on you. No-one wants to waste time, it's as simple as that.

As for the second part -- why not just list a present location and visa status -- that's probably an ok way of going about it. My preference for listing an actual address is that the more detail you give, the more you sound like a real person. You need to consider that if you omit a piece of information from your CV, there's a good chance your reader will pick up on that and wonder why it was omitted. Personally, that's not a risk I like to run, so for anything that I think is important enough for my CV, I ensure that it's documented as completely as could be considered relevant, in the concise fashion that I outlined in the previous article.

But, as Mary has put it, I think I'd read that and feel relatively safe about giving Mohammed an interview, so that's another way to approach the problem, should you not wish to list your address (useful I guess in the case of a "web CV").

Thanks Mary for picking up on that.

CV Advice

It just so happens that over the last few weeks, I've been spending crazy amounts of time editing CVs. I didn't really think I was much of an expert on the subject until sitting down and finding just how easily it comes to me to tear one of these no doubt carefully constructed documents to shreds. I guess I took a bit for granted the idea that everyone possessed some basic level of knowledge about what to write in a CV, but having thought about it some more I've realised that I only have this knowledge because of the sheer number of them that I've read and the tiny number of them that I've read twice.

I think that probably, some people under-estimate the effect a CV has on your chances of getting a job. There's also a bit of a misunderstanding of what these potential employers will actually use your CV for, even amongst those who understand that it's really, really important to have a good CV.

So, before I get into applying you with generous serves of simple advice to make your CV awesome, let me try to explain what happens when an employer needs staff.

Basically this is what happens: you write an ad, you post it on some large job site like seek, then you come in the next morning with 50-100 extra emails than you'd normally get, all from applicants who want the job you're offering.

Now, the thing is, I've got 100 applicants, I need one. Reading a CV properly takes about half an hour, but I don't have 50 hours to read CVs. So what follows is a process where each one of those applications gets at most 30 seconds of consideration. This is just a short-listing process, to throw away the people who are just wrong for the job. To give you some idea of the brutality of this step, I generally go from 100 to 5 CVs in this step. I've read about other people who do this multi-stage thing, but it's not for me, and I don't think I'm uncommon in this regard (to be honest, some people make such a bad impression in their application that I don't even get as far as the CV).

There's a very important message in that: you need to make sure that all the reasons that I should hire you are completely obvious in a 30 second glance. I've read a lot of other pundits who have tried to prescribe what that information is, but I actually think that you've probably got a better idea of that than I do. I will say this: the section that will get most of my attention in those 30 seconds is your work history. I want to very quickly get a feel for what you've done. There's a few reasons for that, but mostly it's just the quickest way to get a feel for what you're capable of, and I do pay a little bit of attention to the general trajectory of your career to date. The thing that will most quickly endear you to me as an applicant is seeing some tangible experience listed, which very closely mirrors the work I want you to be doing. Having a short list of skills early on is a good here -- it will somewhat guide my reading of your work history.

So having got my list down to 5, that's when I'll start looking through your CV a bit more closely, trying to imagine you in my team. This is likely to be about 5 minutes per CV, and I'll have made a decision to interview or not at the end of that 5 minutes.

In the hour before your interview, I'll generally spend half an hour combing over every line, highlighting the bits that motivated me to bring you in for an interview, scribbling notes about things I want to ask about, and forming a map in my brain of how I want the interview to go. That's the third thing to remember.

Before moving on, I want to review those three purposes your CV needs to serve:

  1. The "elevator pitch" -- it needs to express enough in 30 seconds that I'll think about interviewing you. In this pass I'm trying to extract from your CV the stuff that you're good at, whether you're credible, and how can I tie you to the requirements of my job.
  2. To interview, or not to interview -- you passed the 30-second test, if I slow down and take a closer look, do I think you're a close enough match that I should spend some time talking to you? This is likely the part where I will google you, and flip through anything you've written, if it's easy enough to get to.
  3. What should I explore in the interview? -- to some extent this is the least important of the three because it's largely outside your control. If you keep it in the back of your mind though, you'll have some chance of influencing what questions you'll get asked. If you're not talented enough at CV writing to do that, no problem, but do remember that anything on your CV is fair game, so be prepared to talk about it.

Alright, I'll dive straight into sharing with everyone the advice I've been handing out. The point of the above snapshot into my world of recruiting is that keeping in mind the process, and the distinct types of scrutiny that your CV will be subject to, will help guide a lot of the decisions you make. The stuff that follows is just the basics, really, it's bland and generally applicable, and forms a sort of baseline standard.

Here goes:

  • The filename of your CV should be 'FirstnameLastnameCV.doc' -- employers get hundreds of these things, so you should make it as convenient as possible to find yours amongst the myriad that will be sitting on their filesystem. Also, while I sympathise with an affection for pdf, most recruiters have an affection for Microsoft Word and there's just no point fighting it.
  • Put complete contact details in. Anyone who's actually interested in hiring you will want to talk to you, so put a mobile phone number there at least. And, while it's absolutely racial discrimination, if you've got a slightly unusual name, putting a street address will put employers minds at rest that you are in fact an Australian resident and they don't have to worry about visas or whatever. It's just better to put it in there and not worry about missing jobs because of it. They won't letter bomb you.
  • In your employment history, in each of your jobs, each sentence needs to start with a verb that expresses what you did. Not just any verb! "worked" is a useless verb. I know you worked on stuff, that's why it's in your work history. Verbs like developed, managed, lead etc are the kinds of words you want to use. As an example, here's a line from a CV I read recently:
    Worked as a member of a small team of Engineers developing the XXX server in Felix.
    "Worked" is bad. The thing you did was "develop", but that's at the end of the sentence; it's too likely I'll miss it in the 30-second pass. The teamwork aspect is in there, but reading this, I don't get any idea of the scale of the team (small means many things to many people; saying "small" comes across as "so small that I'm embarassed to say"), and communicating that kind of detail will lend credibility to what you're saying, as well as make it more meangingful. Finally, the skill that this line should express to me, that you can write Felix code for server apps, is buried right at the end of the sentence. I would write that line like so:
    Developed server application in Felix for XXX project in a team of n people.
    Putting what you did at the start (developed), what it was you did that to next (a server application), and then other details, wrapping up with an objective statement about the team size. And remember: talk yourself up.
  • On layout: your CV will likely get mangled by recruiters, so you need to make it resistant to hack-and-slash reformatting. Use 'Times New Roman' as the font. The only possible exception to this is on headings, but make sure whatever you use is a font available on a default install of Windows. I suggest you eliminate any reliance on horizontal formatting. Make the body and the title of each section align to the left margin of your page. Put the job-titles in bold in your employment history so it's easy to navigate the document.
  • Eliminate redundancy, it really bothers people in a hurry. Saying 'Wrote unit tests...' is not sufficiently different to 'Wrote a regression test framework...'. I'm sure both are true, but you can get that into a single bullet point. Your aim is to get a chance to clarify that in the interview that you're hoping to get.
  • Make your sentences shorter. When you've got to read hundreds of these things, you really only pay attention to the first couple of words. Worse, you tend to stop reading bullet points toward the end, so put the most important stuff at the top of the list. Aiming for brevity will force you to prioritise important stuff.
  • It's good to list a team sport in your interests if you can, it suggests that you'll work well in a team.
  • Only put a 'career objective' section in if it's going to help you get this job. If you're just applying for the same kind of job you had before, it's probably not so important. The reader will know what kind of job you want, because that's what you're applying for. Stuff like '... further my experience in ... to pursue my primary professional interest of ass-kicking' or something is what you want to say here. I generally don't advise having such a section unless there's a good reason to explain why you're applying for what you're applying for. If you do have such a section, think very hard about what you want it to say. This is the first thing you're putting on your CV -- make it count.
  • Spell-check!
  • Punctuate correctly. Make correct use of apostrophes at least.

Finally, be prepared to have a few versions of your CV that highlight different aspects of yourself. Odds are that there'll be jobs that you're thoroughly qualified for, but this CV won't say that. If there's a job you really want, take the time to re-work your CV for that particular job. Aside from that, identify a few different focuses you're interested in and prepare CVs for each one. It'll mostly be re-ordering stuff and eliminating irrelevant sections, but it's worth doing.

Good luck! mail me if you've got any questions or suggestions.