User friendlessness
Anybody who’s known me for any length of time knows I’m an advocate of the end-user in software development. I think the contempt that programmers show for end-users is a disease. I’m hardly unique in this. A quick search of the usual suspects in tech blogs finds a lot of support for this position… with one odd oversight.
Where I seem to differ from my former colleagues is in thinking that programmers are end-users too. If you take a look at programmers’ tools, however, and compared them to equivalent tools outside of the programming craft, you’d be shocked (if you’re honest with yourself) at the disparity.
Programmers are treated as second-class citizens to even the “lusers” that they themselves deride so often.
The symptoms
Programming tools include everything (I mean everything) programmers use to make software. This includes programming languages, library suites, operating system services, text editors, debuggers and even the word processors programmers should be using to write documentation. (More on that below.) When you look at these, however, you’ll see that the tools are very badly constructed.
- They’re limited in scope and difficult to integrate with other tools (gdb, the autotools suite, Vim).
- They’re massive stovepipe systems that pretty much demand you commit to them and them alone if you want to use them at all (Emacs, Eclipse).
- They’re poorly documented to the point that the lore of experts is the only way to really get ahead (Ruby on Rails, 99.44% of
F/OSSlibraries, Erlang’s standard library). - They’re inconsistently constructed so that knowledge of one portion can actively harm knowledge of another (Win32, Erlang’s collections, Common Lisp’s entire library).
- They’re filled with loads of mind-numbing ceremony necessary for even the most trivial work (Java, C#).
- They’re filled with redundant information that is a regular source of error as one part is updated without another part getting properly updated as well (Java EE or pretty much any other “enterprise” software package).
- They use a model of modularity that breaks so frequently a minor change typically involves a massive rebuild (C, C++ and any other language that uses textual inclusion instead of proper modularity).
- They have poorly-defined semantics around their abstractions with a lot of harsh, sharp corners to catch on (C, C++, Java, C#, JavaScript, PHP, Ruby, Python… let’s face it, pretty much every popular programming language and most of the unpopular ones).
It’s almost as if even the developers who do understand that they are writing for their users have forgotten that programmers are end-users too whose productivity is nuked when (not if!) their tools suck.
So let’s take a look at a few common kinds of failure.
Verbosity (you know, just like this rant!)
Go take a look at Hello, world implemented in a bunch of different languages. Look at the ceremony surrounding some of the popular programming languages in this simple task:
Look at other languages as well, the ones that aren’t popular (or even known, for that matter!). There are quite a few doozies in there. Component Pascal, for example, or Modula-2 or Dylan.NET or elastiC or Fantom or Mercury… you get the idea.
Now the “Hello, world” program isn’t quite a fair test of a language because sometimes the ceremony is there for things that really only start to apply when you deal with non-trivial code. That being said, there is room to argue that you shouldn’t need to use the ceremony until you, well, need it. And seven lines to say “Hello, world?” That smells quite a bit. (It’s amazing to me when COBOL, of all languages, is less verbose than others!)
The real check is how much of that ceremony scales. If you only have to type the ceremony once and then have the rest of the code be mostly compact and concise, then this opening ceremony is tolerable. If, however, you have to wrap everything in equivalent ceremony with every piece you touch (I’m looking at you here, Java, and even more so at Java EE!) then the code rapidly balloons out of control and into the realm of the unusable.
Documentation
This is a pet peeve of mine, to be honest, so feel free to tune me out here and skip to the next. F/OSS libraries in particular are guilty of this, but most software is to some extent or another. Documentation, if it exists at all, is purely reference documentation. There’s no tutorial documentation (which is ironic given how much pointless ceremony is attached to most libraries!). There’s not even a birds-eye overview user guide.
Now my examples here are going to come from the Erlang/OTP distribution. This is not because I hate Erlang (quite the contrary!) but rather because it’s the documentation I’m most familiar with. Here are some documentation sub-failures to look at. (There are many more and I could write a whole blog series on documentation that sucks.)
Hard to find
Erlang’s I/O system is based on a notion of “group leaders”. It’s an important concept that you actually do have to understand if you want efficient I/O in Erlang. Pity that it’s basically undocumented. Do you think you’ll find it on erlang.org? Fat chance! Here’s where you find it (and that only when trapexit.org is actually up and running). Or you can infer it, of course, by Using the Source, Luke.
This is really bad documentation for such a vital feature. Why it languishes in an external document referenced from a third-party forum is beyond me.
Addenda and Corrigenda
An astute reader has pointed out that there exists hints of documentation for the group leaders. The erlang module does mention group leaders in passing in the form of two API calls. It doesn’t explain what any of it means but you get a hint of their existence here.
There is also documentation now on the I/O protocol which goes into more detail on group leaders. It doesn’t explain the rationale at all, but it at least shows you the nuts and bolts of its operation. This is an improvement, but still fails to be good documentation because knowing how to do something doesn’t help if you don’t know when or why.
Further, the erlang BIFs module uses the term “group leader” but there’s no link between the docs and the second document uses completely different terminology. If you don’t have access to a guru to point you to Robert Virding’s “Erlang Rationale” paper you would not be able to link the concepts without using the source. If even then.
Utterly incomprehensible
Those people who know me in the Erlang community know of my deep and abiding hatred of the sofs module. I’m sure it’s a good module in terms of it being well-written and useful. It’s just that its documentation is quite possibly the worst documentation I have ever seen anywhere. Having no documentation would, in my opinion, be superior to what’s there.
The documentation begins, for some bizarre reason I can’t fathom, with a long screed on set theory. It defines terms that no programmer shouldn’t already know: empty set, equality, intersection, subsets, disjoint sets, etc. etc. etc. It then leaps straight into a description of the data types and functions in alphabetical order: pure reference documentation, in other words. And even there the documentation remains bizarrely unhelpful. Consider this gem from the first exported function:
“Creates a function. a_function(F, T) is equivalent to from_term(F, T), if the result is a function. If no type is explicitly given, [{atom, atom}] is used as type of the function.”
What’s missing from the sofs documentation? Well, quite frankly, the actual documentation. There’s nothing showing the lifecycle of sofs usage. When using sofs, for example, what function do you use first? (Hint: set. Or from_term. Or from_external. Or from_sets. I’m guessing on all of this, though.) I suspect that sofs is badly underused and that is mostly because of its documentation.
Uncivilized APIs
A perfect example of uncivilized APIs again comes from the Erlang world. (Seriously, I’m not harshing on Erlang because I hate it! I love it and just use it for examples because I know it!)
Look at the collections in Erlang. The dict module and the orddict module, for example, are identical in their interface (with a potentially nasty semantic difference buried in the Description section). Now look at the gb_sets module. Despite many operations being similar (you insert items, delete items, etc.) the function names are not. If you choose to change your data representation from a dict, say, to a gb_set, you’re rewriting all your code. This is annoying and acts as a barrier to experimenting with different data representations.
A civilized API would, in the specific case of collections, ensure that similar operations (insert and delete, say) have the same name and the same order of operands, etc. This is not the case in Erlang’s collection set.
Of course uncivilized APIs spread far beyond Erlang. Let’s look at Microsoft’s Win32 API. CreateFile is a good example. Look at the massive ceremony surrounding just creating (or opening) a file! Seven—seven—parameters, two of which are “optional” (which means 99.44% of the time they’re going to be NULL and thus merely clutter the interface for no good reason). And that’s not all, of course. There’s also CreateFile2, CreateFileTransacted and LZOpenFile to brighten up your day. And, of course, you CreateFile whether you’re opening an existing file or, you know, actually creating a new one. (Why? Because CreateFile actually means CreateFileHandle. Which brings up the other piece of stupidity. You Create a File but you Close a Handle. Because after making one of the most comically verbose APIs available for a very basic operation, of course you’re going to make things “easier” by having a single function to close everything from files to windows to threads to… well, practically anything. Except sockets.)
Stovepipe systems
Emacs is a(n in)famous tool for programmers. Many top-notch developers swear by it. Many others swear at it. What nobody can deny, however, is that if you use Emacs, you go into it all the way. There’s no such thing as a casual Emacs user because if you’re using it only casually you’re not getting its purported benefits. Using Emacs is a lifestyle choice, not a programming tool.
Emacs also, quite infamously, doesn’t play well with others. While I’m not a huge fan, necessarily, of the “standard” GUI way of doing things, the fact that it is a standard is important. I can switch from Microsoft Word (pre- that stupid “ribbon” thing, I mean) to Abiword to LibreOffice Write to pretty much any end-user oriented software product without any difficulty; I’ll be reasonably productive in it in a day and will gradually ramp up to all the shortcuts and power user things I need as I get used to the changes. This even extends to the Ctrl+C/X/V thing: in any GUI program anywhere I can Ctrl+C to copy text and Ctrl+V to paste it.
Except Emacs.
Emacs has to do everything differently. This is, in fact, why I don’t use Emacs. I use enough other programs that Emacs sets up loads of destructive interference that damages not only my text editing productivity but also my productivity in unrelated tools like spreadsheets or word processors or even web browsers. I’m not willing to do everything in Emacs (and I know you can!) so I’m not willing, as a result, to do anything in Emacs. It’s just too alien.
Now the same can be said for my editor of choice: Vim. It is, in many ways, even more alien than Emacs. It is, however, significantly simpler (being a much more limited tool!) and thus easier to partition away into “I’m doing Vim so I do this; I’m not doing Vim so I do that”-style handling.
Eclipse is almost as bad. It uses standard GUI conventions, but it pretty much demands that you do anything development-related in it. You must use it for editing, debugging, project management and pretty much everything else. If you don’t, well, lots of luck figuring out where it tosses things. (Its configuration files are a nightmare and I’ve frequently found myself changing things that aren’t reflected in the IDE itself for reasons I couldn’t fathom.) It’s not as bad as Emacs, but it’s still sufficiently bad that I don’t use it. I’d honestly rather have a window for editing (vim), a window for a REPL (if applicable) and a window for executing my builds, tests, etc.
This is going on too long…
Let’s face it, the world of software development tools is in a really bad way. As much contempt as programmers show their end-users, they show even more for their own kind. (I’m pretty sure a good Ph.D. thesis is awaiting anybody who wants to study this self-loathing.) The real tragedy here is that everybody’s productivity would be enhanced if everybody worked only a little bit more on the usability aspects of their software development products. As things stand now, however, development tools are almost the epitome of user friendlessness.