I wrote this one early on in 2007 and it is still one of my favorites…
Look at just about any successful open source project, anything from Java’s Tomcat or ant to Ruby’s Rails, and there is one thing they all have in common. They all work right out of the box. Download any of these masterpieces and a few minutes later you will have something running. It may not be much, it might only be a “Hello I’m working” web page, but you will have something going, something to tell you that the people who wrote this thing are really trying to help you move along.
Now here is something to consider: do all of these packages work right out of the box because they are successful, or are they successful because, somewhere in their early days, they were easier to set up then the competition? I’m not sure. But one thing I do know is that making it easy to get your code up in running is absolutely critical to getting people to try it. This applies to a one person open source project just as much as it does to a major commercial production. And the converse is also true: “I played with it for 20 minutes and couldn’t make it work.” is about as damning a review of any software as I can think of.
So how do you make your stuff work out of the box? Well a lot depends on the details: delivering a working web app is a lot different than putting out a working standalone application. Still there are some general principals:
Scripts and batch files are not optional
One thing that is guaranteed to annoy your users is to use them as a command interpreter. If you find yourself writing documentation that sounds something like this: “Now cd into the utilities directory, and run the setup_files script. Then cd up one and down into the lib directory and copy foo.dat to bar.dat…”
How about this:
#!/bin/sh cd utilities ./setup_files cd ../lib cp foo.dat bar.dat
Remember, you have about five minutes to convince a prospective user that your thing is great, that you know what you are doing. You can have them spend that five minutes playing with your masterpiece, or pretending to be the Bourne shell. It is up to you. Services serve me, right?
If you are writing some kind of service, something that is supposed to start up when the computer starts and shutdown cleanly when the computer is going down, you can make your users love you by supplying the plumbing to allow them to do that easily. On Windows this means getting one of those “make me into a service” wrapper programs – it’s been a while since I have dealt with the Microsoft side of things so I won’t pretend to give advice here, except to say, don’t leave it out.
On the Unix side, you really need to supply those init.d type scripts. These are the scripts that Unix systems use to start up and shut down services. Most Unix flavors keep these scripts in /etc/init.d and if you are writing a service type thing they really are not optional. Or to put it another way, many of your competitors are going to leave these out – certainly a lot of expensive “enterprise” packages do – and you can get some user points for just including a few simple shell scripts.
Some programmers have this fatal fascination with fixed directories. Oh, I’ll just design my stuff to run out of /usr/acmesoftware. Or C:\AcmeSoftware. The thinking is that if I just assume that my stuff is in some well know directory, all my code becomes much simpler. Well, as my example above shows, not really. Is your code running on a Unix box, and out of /usr/acmesoftware or is it C:\AcmeSoftware? You do want people with the other operating system to be able to use this thing, don’t you?
No, marrying your code to some specific directory does not really make your life all that better, but it will make people who try to use your stuff hate you. What if your user doesn’t have permission to write to /usr/acmesoftware? Love your code, sorry can’t use it. What if they like your stuff so much that they want to try out five or six different configurations at the same time. What, I can only run one copy of your thing at a time? Next!!
Your software should run out of whatever directory the user drops it into. It should run out of /usr/acmesoftware, but it should also run out of /home/fred/projects/test1/as and out of C:\tmp. And anywhere else.
The problem is, many programs need to know where they live, so that they can find jar files or libraries or data. That is why we tend to fall back on the ‘well known directory’ thing. Well you can do better: If you are writing a standalone app on Unix, your start up script can actually figure out where it lives. You simply add some code that looks like this:
PRG="$0" progname=`basename "$0"` MY_HOME=`dirname "$PRG"`
Actually, if you want to handle symbolic links you have to work a little harder than that, but there are plenty of examples: look at the bin/ant script that comes with ant or the bin/startup.sh script that comes with tomcat. I don’t think you can make this trick work on windows, but you can at least make some intelligent guesses: ant.bat tries to figure out where ant is installed by looking on the system drive, in Program Files and in a few other likely places. If all of this fails, you can always fall back on an environment variable, but before you do, make sure you read the next section. No environment variables. Well OK, maybe one.
Another way to drive your users into a programmer hating rage is requiring them to set 137 environment variables before your application will say boo. Particularly obnoxious is the habit of requiring a whole bunch of variables that could be derived from a single value:
export ACME_HOME=/opt/acme export ACME_BIN=/opt/acme/bin export ACME_LIB=/opt/acme/lib export ACME_CONF=/opt/acme/conf ...
Usually the only environment variable that is excusable is the one that says where you stuff is installed – but read the previous section first. You can almost always figure things out from there. This doesn’t mean that you can’t look for all 137 environment variables: just don’t require them.
Oh and Java programmers take special note: everything I’ve said above applies 8,526 times to CLASSPATH. Surely you know more than I do about what class path you are looking for. Yes, if you are just writing a simple utility class you are going to be dependent on the user’s class loading environment. But the number of full blown Java apps out there that simply expect me to figure out their CLASSPATH is astounding.
Help me here.
Deal with file permissions
We Java types tend not to think much about the lowly jar file, but it really is great to have a widely accepted, Java centric archive format, which is even cross compatible with zip. Good job JavaSoft. Unfortunately it just doesn’t handle file permissions. This tends not to matter very much on Windows, tends to be less paranoid about which files are executable, but it plays Hell with Unix programs and scripts.
What is a coder to do? Well you can deliver your stuff with tar or rpm or one of the other formats that does handle file permissions. This is what tomcat and ant do. Or you can supply a script that sets all the permissions and have the user deal with that script and only that script. Lately you can even deal with permissions from within your Java code itself, sincel late model versions of Java now have the ability to set file permissions from within a program.
I always thought the old bit of wisdom that “no man is an island” got it exactly backwards. Most islands are submerged mountains, the visible green part at the top the tiny tip of a huge, invisible supporting mass. Looked at from this point of view, any given piece of modern software is quite definitely an island, held up out of the ocean by a vast bulk of libraries, VMs and jar files. And if only providing the proper support for today’s hyper dependent apps was a simple matter of producing a few million tons of volcanic rock, life would be easier. At least geologists don’t have to deal with 87 thousand different versions of granite, all incompatible and all refusing to live in the same crust as those other versions.
Every programming language has its own version of DLL Hell: Ask any Java programmer about dueling versions of Jar files or any Ruby programmer about conflicting gems.We programmers need to deal with this all the time, but we don’t have to foist all this on the user. Try to supply your user with all of the parts that he needs, the right versions of all the jar files, libraries, xml config files, whatever. Documentation yes. Victorian novel no What I want out of life is a complete set of Spiderman comics, an end to lite beer, and a one page quick start guide to getting your app up and running. In a pinch I could give up the comic books. Why does software seem to always come with no documentation or way, way too much? While the no documentation option (silently) speaks for itself, the way too much one is more complicated. Yes, by all means tell me as much as you can about the genesis, care, feeding, upkeep and quirks of your application. But also please help me get started, help me get going. I’ll give you 5, 10 minutes before I give up on your stuff. Make me productive in that brief time and we may have a start to a beautiful relationship.
I’ve saved the most obvious, and possibly the most ignored bit of advice for last. If you actually want your software to work out of the box, you have to do the following: Package it up Get yourself a clean system Install your software onto the clean system See if it works. If it does not, fix the problem and go to step 1
I told you it was obvious. So why is it that so many programs that I try have obviously not been tested against a clean environment. I frequently run into programs that are looking for C:\BILLYBOB or /home/fred/development. Easy to fix – for Fred or Billy Bob, maybe not so much for me. A little testing goes a very long way.
Writing software is not easy. Writing working, complete and usable software is down right hard. But the trick is to try and put yourself in the place of the person who is going to use your stuff. What is is likely to have on hand? How much is he going to want to invest in trying out your thing? Then try to make those first 10 minutes work for you.