04-14-10 - Friendly Apps

A recent post by Multimedia Mike is about something that I advocate which I think most people don't do enough of : make your app easy for yourself to use. Developers too often think of usability as an annoyance which they have to do for end users, and they will struggle and deal with great annoyances when they use their own apps themselves. This is ridiculous, you are your most important user. Mike mentions a few good things, I'll repeat him a bit :

1. Make good defaults. Make things that you always want automatic. With every command line option, ask if you usually want it on or off, and make the default the thing you usually want, and then make the option to turn it off. Be aggressive about "refactoring" over time. If you find that you have to type a million options to run your app right, something is wrong. If you have trouble remembering your own options, something is wrong. Another detail : make options automatically turn each other on. For example when I enable "heavy prepass mocomp search" I now also automatically enable "save motion to disk cache" because I pretty much always want them together and I kept running mocomp search and forgetting to enable saving it to disk.

2. Make full logging and saving the default. You never want to run your app and have it produce some weird results or crash or something and have no record of it because your forgot to enable logging. Full logging should be on by default, and only disabled from the command line in weird cases. All my apps now automatically write logs to c:\logs\appname.log using argv[0] automatically. My video test app also writes a log for each run which is named with the date and time so that I have logs of every run ever. Each log also writes out info about the build and the command line options so that I am never left thinking "WTF run was this?". (Actually there's one thing I'm still not doing here that I really should do, which is to record the sync state of perforce that was used to build the current EXE ; we had that working at Oddworld and it is the fucking bomb). This is a variant of the Carmack adage that "no time spent visualizing your algorithm is ever wasted" ; my variant is something like "no amount of logging is too much".

2.1. Make clean versions of your logs and output! Just because you are logging tons of detail, that's not an excuse to just output a ton of shit that is impossible to parse. You might need a "detailed log" and a "summary log" ; certainly don't just spit it all to stdout. If you find yourself having to go through the log constantly to find the little bit of info you actually want, pull that bit out and format it right. Do computations for yourself in the app instead of doing them afterwards. eg. I found I kept going into my logs to get the total lagrange J, so make your app compute it for you and display a nice clean summary at the end. But try to avoid just numeric summaries, instead output CSV's and stuff with more detail, charts and graphs so that your human brain can see patterns and problems. You want to present things to yourself just like you would in a technical talk to your peers - make it clear and pretty, that helps you to parse the data on an intellectual level.

3. Never fail your app because the user forgot to do something obvious - instead make the app fix it. For example if the user gives me output file names which are in a directory that doesn't exist, I make the directory. I wrote a big rant about this long ago which still stands, about validating user options *before* you do your two hour CPU crunching. You should definitely do that, but even failing that you should simply not fail ever. For example if you for some reason cannot validate file names before your run, then if you fail to open the output file, just output to c:\fallback_output or something.

4. Make the app automatically do things that you always have to do. eg. I have to preprocess some video formats before I can read them - fold that into the app so it gets done for you automatically. This kind of stuff has merit in the short term just because it saves time and aggravation, but it has *loads* of merit in the long term when you come back to some work after months away from it and you can't remember how the fuck to make your app work any more - if it's all in the code and it's all automatic you don't have to remember the complicated process of how to use things right. Similarly, app parameter ranges should be clearly documented and preferrably rescaled into reasonable ranges. Say your take a lagrange lambda parameter and reasonable ranges are like 0.0001 to 0.002 ; that's damn annoying, so rescale to expose it as [0,1] to the command line.

5. Be flexible in how you parse command line args. Write a proper flexible parser once and be done with it and stop writing cheap hacky parsers for every new app you write. For example I don't want to have to figure out whether your app wants "-i7" or "-i 7" or "-i=7" or "--i7" , just accept all of them and stop bothering me.

People tend to cover up a lot of this stuff using perl scripts or batch files or whatever, which is okay to some extent *IF* you check in and document your scripts/batches the same way you do your code. The problem is that most people are very sloppy/lazy about their helper scripts, so they become broken and undocumented over time and you still have the problem where you come back to something after a year and are like "fuck how do I run this?".

No comments:

old rants