Tools and interface - FLAC to MP3 for iTunes on console

From the beginning of my journey with programming, many times I've been reminded of the importance of a beautiful, seamless user interfaces. The whole topic is very broad, so today I will focus on a single problem – the problem of having to remember the exact way of input for a program to perform a certain tasks, and how we can mitigate or dodge the problem entirely, while going through the process of designing a script that makes adding FLAC files to iTunes by console a breeze.

There are many things we are good at remembering – for example, one of the more difficult problems for robotics of the last and current decades was developing a way for robots to handle movement, something we "just do". If an alien race were to ask us where and how long we were learning to be able to walk, run, climb and do many complicated movements at once, many of us would answer that they were never learning these (which is wrong, but understandable given the fact most of us do not remember any of their early childhood period). Once learnt, skills such as swimming and bike riding stay with us till death.

Robots have trouble with movement, but are excellent in saving and remembering arbitrary symbols. If I told you a few words and numbers and asked to come back in two weeks and tell me these once more, most probably you would like to write these down and if that would not be possible, it would totally depend on your abilities and what I told you about how important these numbers are to you. A computer on the other hand will remember this for indeterminate amount of time with no hassle.

The same split can be observed with tools we use.

A screwdriver is a tool that needs some mastery in order for the user to be fast and efficient. It's a manual tool, however. If you learn the movement even if it's complicated to do it proficiently you'll still know what to do with screws many years later.

A command-line tool needs some input (problably a name and some arguments) in order to deliver expected output. However, I catch myself that for some tools that I use rarely, each time I need to bring up the help file for the tool in order to run it. This is a signal that I am failing to do the work my computer would happily do for me instead.

The case of a general tool and specific case

In this specific case, my use case was to be able to import lossless music in FLAC format to my iTunes application. ITunes cannot play this format, and I don't want for lossless music to consume large amounts of space on my drive, so I found a tool to convert the music to the MP3 format. And I feel just right to use terminal or console to run such tasks, so after a brief search I've found the flac2mp3 script.

This is a great tool, however, every few months I need to use it I forget the parameters I'm typically running the script with: --preset 320 and --processes 5 accordingly. The original tool is too generic for me, as it supports variety of different parameters thus forcing me into remembering ones I need to enter. I need to enter two directories for source and destination, which in my case means I am going to write flac2mp3 [...] "Some Artist - Some Music Album [FLAC]" "Some Artist - Some Music Album [MP3]", which I could make shorter in Bash, but it needs me to actively think on how to approach entering this command.

(This is by no means an error of the script's author, though – he wrote it for many different users, whose needs may be completely different from mine. The tool can also do much more, e.g. process a whole disk of FLAC files in a single command, which could come in handy once in a while.)

But from the standpoint of my interaction with the program, it is not seamless and beautiful. The process is at least a few steps to be executed in order, some parameters to remember, and in the case I forgot something, I need to backtrack in my step list, read help, understand it and then return to my process of bringing the music to iTunes.

Problems and solutions

What could be done to make it better? A developer might add a preferences file or RC file where I could override defaults. Guesses can be better, the --processes option could automatically choose number of processors/threads a computer has. I'm writing these options for the sake of completeness, I actually am happy that the original author had written a tool that does 99% of the work for me. But from UX perspective it's important to question what is the frequency of different goals that can be achieved by using this tool and branch out interaction towards different groups of users.

On the other hand, tailoring the general script to one's needs is much simpler. And this is what I'm doing in the following Gist:

There are a few things to be mentioned.

First and foremost, anyone copying this gist has a way to provide different options from themselves or even simply remove the code that integrates with iTunes (or change it to move to their own Music directory instead of iTunes). So you do not need to remember any optional parameters.

Furthermore, if you issue a command in a wrong way, you'll get a usage message. A usage message/help message (or both) are mandatory and this is why libraries like docopt are in my opinion great inventions for developers to write their programs self-documenting.

The third – try the hardest to make your program work with the least parameters possible and make good guesses for others. In this case, you can omit target directory and the program will still work - it will try to change FLAC to MP3 in the directory, and if this is not possible, then it will append [MP3] at the end of the directory's name.

Fourth - make your programs composable. There are three functions in this gist. One simplifies FLAC -> MP3 conversion to a single-parameter command. Instead of typing:

flac2mp3 --processes=5 --preset=320 <FLAC_DIR> <MP3_DIR>

You need to write:

flac2mp3 <FLAC_DIR>

The second one moves a directory of MP3 files to iTunes. The third one does both tasks at once and has the same interface as the first one.


Computers are good for storing data. Humans are not good for storing data, but they are used to patterns. If you follow these patterns, you'll make a tool that is human-friendly. So in points, when making any tool:

  1. to prevent forgetting, allow setting custom defaults;
  2. and make the most intelligent guesses you can to avoid the need;
  3. minimize required parameters;
  4. follow the intuitive patterns - it's easy to guess what comes next after the program name in a program that can convert ...
  5. do all of this because we are not good in remembering arbitrary symbols. We have computers for that.

As you can see, even console tools can have beautiful UX - they are also good as learning examples, mainly because without graphical bloat we are able to discuss specific cases and rules, a trait that can be blurred by introduction of custom GUI.