1. define the interface

    1.1 define a clear and concise purpose

    1.2 choose between a simple command-line application and a command suite

    1.3 define options, arguments and commands

    • single command-line app: options without arguments (switches), options with arguments (flags), arguments

    • command suite: global options (with and without arguments), commands, command options (with and without arguments) and arguments

    1.4 use short-form, long-form and negatable long-form options

    1.5 choose default values for flags and arguments

    • make common tasks easy

    • make uncommon tasks possibile (but not easy)

    • make default behavior nondestructive

    1.6 validate arguments to flags

  2. code

    2.1 choose a library (or roll your own)

    2.2 structure the code tree following standard Ruby conventions (lib, …)

    2.3 apply OO design principles and patterns (wisely)

  3. add configurability

    3.1 use a YAML-based configuration in a dotted .rc files placed in the user’s home directory

    3.2 create configuration file at startup, if missing, and notify the user

  4. embrace interoperability conventions

    4.1 use the standard input and the standard error streams appropriately (Open3, STDOUT, STDERR, $stdout, $stderr)

    4.2 use the standard input stream as the default source for input

    4.3 use standard exit codes to report success or failures

    4.4 provide pretty-print and machine formatting options, choose the default and switch based on the context (STDOUT.tty?)

    4.5 trap signals sent from other apps

    4.6 name files uniquely and in common locations (such as /tmp) to avoid collisions

    4.7 do not delete or overwrite files as a side effect without explicit instructions from the user

  5. add documentation

    5.1 don’t forget the inline help (-h or --help)

    5.2 add a short description in the banner

    5.3 explain options and arguments (and commands for command suites)

    5.4 include a conventionally structured man page via gem-man and ronn

    5.5 generate documentation in the Rdoc format

  6. test

    6.1 apply an outside-in test strategy

    6.2 test user behavior with acceptance tests using Cucumber + Aruba

    6.3 test in isolation with unit tests using minitest

    6.4 use test doubles, if needed, with mocha, construct, FakeFS, …

  7. final touches

    7.1 add tab-completion if possible (bash, etc)

    7.2 add color to the output with rainbow, paint, term-ansicolor, …

    7.3 format output as tables, if useful, using terminal-tables, command_line_reporter, formatador, …

    7.4 enhance the output with formatador, progress_bar, …

    7.5 provide interactive user input with readline

  8. distribution

    8.1 choose a distribution method: RubyGem, rpm with gem2ruby, …

    8.2 manage dependencies with gemspec, bundler, …


References: