Updated
Work-around for Sourcehut bug
SVG test
Go comes with a basic flag library. It lacks some features, or has some anti- features, that has resulted in a proliferation of third-party flag libraries. This is a summarization of some of those libraries.
Sorting is: Deps, ABC, LOC
Library | LOC | Deps | ABC Score | Complexity |
---|---|---|---|---|
clapper | 303 | 0 | 119 | 76 |
sircmpwn-getopt | 501 | 0 | 154 | 60 |
cosiner-argv | 462 | 0 | 155 | 94 |
claptrap | 458 | 0 | 235 | 152 |
droundy-goopt | 596 | 0 | 243 | 162 |
namsral-flag | 764 | 0 | 299 | 162 |
ogier-pflag | 1112 | 0 | 438 | 97 |
opflag | 1161 | 0 | 461 | 118 |
integrii-flaggy | 1732 | 0 | 659 | 303 |
spf13-pflag | 3856 | 0 | 1464 | 583 |
jessevdk-go-flags | 3529 | 0 | 1604 | 1045 |
dmulholland-args | 437 | 1 | 199 | 97 |
thatisuday-commando | 640 | 1 | 213 | 110 |
mwitkow-go-flagz | 1461 | 1 | 487 | 265 |
cosiner-flag | 1821 | 1 | 713 | 463 |
moogar0880-venom | 2029 | 2 | 604 | 303 |
stevenroose-gonfig | 1169 | 5 | 540 | 375 |
peterbourgon-ff | 1060 | 6 | 308 | 231 |
cobra | 4529 | 6 | 1507 | 808 |
dc0d-argify | 348 | 14 | 139 | 96 |
LOC -- no tests, no comments scc -i go -M _test --no-cocomo
ABC Score -- ABC complexity for the project (excluding dependencies) abcgo -format summary -path . -no-test
Here's the real image:
And here's a hack work-around because sr.ht serves the wrong mime-type for
SVG files:
The Complexity column is SCC's metric, which is a sort of cyclomatic complexity derived from counting branches. ABC is a better metric, and the SCC metric is included just because.
ABC metrics are probably the most predictive of the amount of extra size a library will add to code. LOC can be manipulated by formatting and is affected by coding style, but ABC counts branches, assignments, and conditionals, which don't change no matter how many if statements you cram together on a single line. It's also a pretty good indication of actual complexity-for-guessing-potential-for-bugs.
lib | short | long | combined | inverted | env vars | types | choices | commands | varargs | good api | mand/opt | files |
---|---|---|---|---|---|---|---|---|---|---|---|---|
claptrap | Y | Y | Y | Y | N | Y | Y | Y | Y | Y | Y | N |
clapper | Y | Y | N | Y | N | N | N | Y | Y | Y | N | |
droundy | Y | Y | Y | N | Y | Y | Y | N | ||||
sircmpwn | Y | N | Y | N | N | N | N | N | Y | Y | Y | N |
opflag | Y | Y | Y | N | N | Y | N | N | Y | Y | N | N |
namsral | Y | Y | Y | Y | Y | Y | Y | |||||
integrii | Y | Y | y | Y | Y | Y | Y | |||||
jessevdk | Y | Y | Y | N | N | Y | Y | Y | Y | N | Y | N |
Env vars would be nice, but something like GoBike could add env vars and config files, and github.com/subpop/go-ini could add support for config files.
The purpose of this repo is this file. The scripts merely generate it from a
template, calculating and inserting the metrics table. The scripts might be
useful to you; generate.sh
in particular will generate the Data table above
for any set of Go projects you check out into the directory. Do read it, and
especially check the header, because it uses some tools that aren't installed by
default on all Linuxi.
I do this thing every few months where I look for a good flags library for Go. I finally consolidated the process to a script; this is the result.
I mostly like the Go flags
library; it works well in trivial cases, it has
a great API, and it's small. If you look at the profusion of third-party flags
libraries for Go, even just on Github, it's obvious to a casual observer that
the stdlib package falls short for many people. A casual inspection of the
libraries shows that what people are looking for varies greatly; if there's one
common theme, it's that Go's choice to diverge from POSIX getopt
standards
is unpopular.
Having your Go tools handle arguments differently than most of your other tools is unpleasant. While it wasn't possible for Go to conform to standards for every platform, choosing to not conform to the most widely used standard was an odd choice.
Looking at the popular options, it's obvious that many developers don't care if the size of their flags library eclipses the size of the rest of their program. For instance, Cobra -- one of the popular libaries -- is over 4 thousand lines of non-comment, non-test libraries, and has a total ABC complexity of 1,575 and a max cyclomatic complexity of 48 ("complex, high risk").
But who cares about metrics? They're just numbers. Go's flag
library adds
no external dependencies and is usually fine for small, on-off projects, but I
too usually find anything non-trivial gets hard to manage with the stdlib. What
I look for in a flags library:
flags
; I don't want to have to build structures to parse
into, or use something that feels more like a framework than a library.flags
library to double the size of my program.-a -b
~= -ab
)-n 1 -n 2 -n 3
)In more involved applications, there are some other features that are pretty useful:
--recurse
gives you --no-recurse
)The last three are easily done in code outside of the flag library, but having the data validation built-in reduces errors.
There are two other features which I really like, but start to feel like feature envy, and -- indeed -- libraries exist for supporting these outside of flags.
GoBike-envflag
extends the
stdlib flags
library to support 12-factor env variable support, which is
awesome! It fails as soon as you start using a third party flags library,
though.What's the moral? If you want something done right, do it yourself. I ended up writing claptrap, which implements everything I want, how I want, without being a monster framework disguised as a library. Claptrap actually started out as a set of PRs for clapper, but in the end with maybe 20% of the original code and 60% of the original API, I just forked it off into a different project.