
The importance of user interface, illustrated by the Go flag package - zdw
http://utcc.utoronto.ca/~cks/space/blog/programming/GoFlagUIImportance
======
sirclueless
The go flag package has a nice API, but the user interface it creates is
straight from its Rob Pike's Plan9 roots, and Linux users familiar with getopt
command line interfaces will find it strange and perhaps even ugly.

I wanted to create command line programs that look like traditional GNU/Unix
utilities, so I wrote the
[https://github.com/ogier/pflag](https://github.com/ogier/pflag) package. It's
a drop-in replacement for the flag package, just change the import line. It
also adds some basic features, such as the common pattern of a flag with a
long-hand form usable with a double --dash and a shorthand character with a
single -d.

~~~
rsc
The Go flag package has nothing to do with Plan 9. Like Unix, Plan 9 had
single-dash single-letter options ONLY. The long option syntax of getopt is a
BSD/GNU-ism, not from Unix.

The Go flag package's command lines adopt the observation made by the Google
C++ command line flag parser
([https://code.google.com/p/gflags](https://code.google.com/p/gflags)): the
long/short --/\- two-names-for-every-flag dichotomy was useful for backwards
compatibility when recreating original Unix commands, but for new programs, it
doesn't pull its weight. At the cost of requiring that each option be
specified with a separate command-line argument, you can drop the distinction
between - and -- entirely. (This is similar to what X11 programs do, although
I believe they do not admit --x as a synonym for -x.)

It's not clear to me what is "ugly" about _not_ having to keep alternating
between - and -- as you spell out options on the command line.

~~~
munificent
> the long/short --/\- two-names-for-every-flag dichotomy was useful for
> backwards compatibility when recreating original Unix commands, but for new
> programs, it doesn't pull its weight.

Short is more usable for users on the command line. Long is more maintainable
in scripts. That's why it makes sense to have both.

> At the cost of requiring that each option be specified with a separate
> command-line argument, you can drop the distinction between - and --
> entirely.

Again, that cost is high for users on the command line, one of the few places
where every keystroke does matter. It's a lot more pleasant to be able to do:

    
    
        $ rm -rf
    

Than:

    
    
        $ rm -r -f
    

Or, worse:

    
    
        $ rm --recursive --force
    

Orthogonality is definitely an important principle, but when it comes to
usability, it often makes sense to offer multiple ways to accomplish the same
goal for users in different circumstances.

Ultimately, you're interfacing with a greater primate. Even with all of our
nice features, we still don't support USB or web standards. Instead, it's all
lossy OCR and weird muscles. You should expect a certain amount of...
squishiness... when interfacing with something like that.

~~~
codebeaker
I would argue (at the risk of being down-voted) that if you are scripting
tools then it is important to use the long option, not just because future-you
might forget what the options are (relevant XKCD
[http://xkcd.com/1168/](http://xkcd.com/1168/)), but also for searchability,
it's rather difficult in almost any engine (except the wonderful new code-
orientated ones that are cropping) up to search for `-xvzf`, but rather
simpler to search for `extract verbose zip filename +tar`, for example.

~~~
burke
That's really what munificent was arguing too though -- that the long-form
options are preferable for scripting, but that no one prefers "tar --extract
--verbose --compressed --file" to "tar -xzvf" when you just have to extract a
file on the command line (in fact, many people don't even bother with the "-",
"v", or "z", opting for "tar xf"). This optional brevity is important for
utilities.

------
tptacek
I like Go's flag library.

Also: getopt is pretty easy to write (if you're going for strict Unix style,
you're presumably not looking for a featureful getopt), and that interface
style is abused far more often than it's deployed gracefully. Some of the
worst Unix command line interfaces† are the product of getopt, or the belief
that there's an idiomatic Unix argument handling convention and that the idiom
is getopt.

If your argument parsing needs are complicated, you should break out an actual
parser.

Finally: I see the benefit of having an auto-generated usage message that is
better than a bad auto-generated usage message, but if you really want
artisanal command line tools, shouldn't you be writing artisanal usage
messages? C programmers as a rule didn't count on the library to generate the
usage message for them.

† _See for instance nmap_

~~~
kelnos
I think this is missing the point of the article. The author doesn't seem to
care too much about complicated argument parsing needs, just about the
interface that Go's flag library presents to the user.

You touch on the auto-generated usage message: personally I think the one that
Go's flag lib generates is terrible. I agree wholeheartedly with the author. C
programmers indeed don't count on libc to generate the usage mechanism
(though, frankly, if it did, I certainly wouldn't mind), but we're talking
about Go programmers here. And if idiomatic Go is to use the flag library,
then you get an auto-generated message. And it's bad.

I think the other part of the author's gripe is just as (if not more)
important: flag has decided to do away with the difference between '-' and
'\--' options, something everyone has come to expect as standard. In the Go
model, it's weird to have multiple options for the same thing. For frequent
users, typing "rm -rf" is better and easier than "rm -r -f", which is still
better than (what I would think Go would encourage) "rm --recursive --force".
The short options (and ability to chain them without a dash per option) is
great for command-line users, and the long options are great for scripts where
you want clarity and self-documentation.

Being able to make up complicated parsing rules is potentially another
problem, sure, but I don't think it's as important to _users_ of a Go program
as either of the above issues that the author raises.

(For the record, I absolutely love Python's argparse. I think they've settled
on a fair compromise between giving a lot of power, but making the simple
cases simple, while providing behavior and UI that most users of my programs
would expect. Not perfect, but I've been happier with it than with any other
parsing library. Of course, implementing an API like that in a non-dynamic
language that doesn't support optional, named function arguments might be
difficult or impossible.)

~~~
tptacek
Can't Golang programmers just do what C programmers do, hook -h, and provide
an artisanal help message?

~~~
kelnos
Fair point. If the flag lib allows that, sure.

But why should you have to do extra work to override a default that's sub-
optimal from a standardization and user-familiarity standpoint, and is trivial
to fix "upstream" where everyone should benefit?

------
politician
Have you tried docopt? The usage string is a DSL which makes it painless to
create command-line programs with great (and synchronized) help text.

Check out an example:
[https://github.com/politician/azb.go/blob/master/src/cmd/azb...](https://github.com/politician/azb.go/blob/master/src/cmd/azb/main.go#L187-L228)

~~~
gnoway
I think you just illustrated the point of a prior blog post[0] linked from
this one.

[0]
[http://utcc.utoronto.ca/~cks/space/blog/programming/GoGetopt...](http://utcc.utoronto.ca/~cks/space/blog/programming/GoGetoptProblem)

~~~
politician
Wow, that post is spot-on; thanks.

------
zobzu
I cant agree more with the importance of _consistency_ UI in CLI programs.
It's unfortunate that newer programs overlook it.

I'm glad for the recent changes from the flag package which has also been
annoying me previously ;)

When i type blah -h or --help i expect help to pop up. I expect it to tell me
about USAGE with [optional] and <required>. I expect the same spacing and
readability as the vast majority (which is basically dictated by GNU getops.

Else, its a pain. Heck, even git doesn't follow this and as a result is a
little more painful that needs to be.

Imagine a GUI program with every window having a different close, resize, etc
button/menu. Hell.

------
amouat
I agree with this. Docker use the same flag style and it was confusing enough
that it was wrongly documented for a long time:
[https://github.com/docker/docker/issues/10517](https://github.com/docker/docker/issues/10517)

------
martinp
I always use go-flags [1] in my Go programs. It has support for GNU-style
options, pretty help output, subcommands, automatic parsing of more complex
arguments (e.g. time.Duration) among other things.

I do wish they would improve the included flags package though. There are lots
of nice third party packages, but having a proper one in the standard library
would've been better.

[1] [https://github.com/jessevdk/go-flags](https://github.com/jessevdk/go-
flags)

~~~
dvirsky
Came here to say this. go-flags is an excellent package, and makes great use
of struct-tags. An extra bonus is that it can parse .ini files and command-
line flags into the same underlying config struct, allowing one to override
the other.

------
pico303
Try CLI from codegangsta. Quite a nice alternative to flag, with perks--not
the least of which is beautifully formatted help text.

[https://github.com/codegangsta/cli](https://github.com/codegangsta/cli)

~~~
wtf_is_up
I really like kingpin [1] as well.

[1]
[https://github.com/alecthomas/kingpin](https://github.com/alecthomas/kingpin)

------
nkozyra
I hadn't noticed the flag package had changed. I'm not sure this brief post
stressed the importance of UI, though.

~~~
oaktowner
Well, I don't think the writer _proved_ the importance of UI.

But I think it serves as an excellent reminder that, for a cmdline program,
the flags and arguments _are_ the UI, they impact how people perceive your
software and how productive they will be with it.

------
lloydde
This is good news. Being new to go, recently when I didn't get the expected
behavior with a go cmd, not knowing any better I tried explicit =true.

------
lazyjones
I like the present (older) output because it's absolutely unambiguous. If I
have to read a textual description to understand whether it's a default
argument, whether it takes an optional parameter, or how precisely it is used,
it's less clear especially when the text is badly written. The current output
is probably also perfectly suitable for parsing (by a program).

------
mwsherman
The flags package is one of the few Go stdlib’s where I haven’t been won over;
I felt that the cost of my understanding the abstraction was higher than just
implementing the logic.

[https://github.com/clipperhouse/gen/blob/master/main.go#L67](https://github.com/clipperhouse/gen/blob/master/main.go#L67)

------
Animats
Could be worse. There's a build tool for Mozilla add-ons where the flags go
_after_ the file argument.

------
tomcam
Couldn't a perfectly adequate parser have been written in about the same time
as the blog post?

