Directrices para la Interfaz de Línea de Comandos

Una guía de código abierto para ayudarle a escribir mejores programas de línea de comandos, tomando principios tradicionales de UNIX y actualizándolos para la actualidad.

Contenido

Autores

Aanand Prasad
Ingeniero en Squarespace, co-creador de Docker Compose.
Aanandprasad

Ben Firshman
Co-creador Replicate, co-creador de Docker Compose.
Bfirsh

Carl Tashian
Desarrollador de Smallstep, primer ingeniero en Zipcar, cofundador Trove.
tashian.com  @tashian

Eva Parish
Escritor técnico en Squarespace, colaborador de O-Reilly.
evaparish.com   @evpari

Diseño de Mark Hurrell. Gracias a Andreas Jansson por contribuciones tempranas, y Andrew Reitz, Ashley Williams, Brendan Falk, Chester Ramey, Dj Walker-Morgan, Jacob Maine, James Coglan, Michael Dwan y Steve Klabnik por revisar drafts.

Acompáñenos en Discord si quieres hablar de la guía o del diseño CLI.

 

ANTES que nada

En la década de 1980, si querías que un ordenador personal hiciera algo por ti, necesitabas saber qué escribir cuando te enfrentabas. C:\> o ~$. La ayuda vino en forma de manuales gruesos y en espiral. Los mensajes de error eran opacos. No había un desbordamiento de Stack para salvarte. Pero si tuvieras la suerte de tener acceso a Internet, podrías obtener ayuda de la comunidad de internet temprano de Usenet’an llena de otras personas que estaban tan frustradas como tú. Podrían ayudarte a resolver tu problema, o al menos proporcionarle algún apoyo moral y camaradería.

Cuarenta años después, las computadoras se han vuelto mucho más accesibles para todos, a menudo a expensas del control final de los usuarios de bajo nivel. En muchos dispositivos, no hay acceso de línea de mando en absoluto, en parte porque va en contra de los intereses corporativos de jardines amurallados y tiendas de aplicaciones.

La mayoría de la gente de hoy en día no sabe cuál es la línea de comandos, mucho menos por qué querría molestarse con ella. Como dijo el pionero de la computación Alan Kay en una entrevista en 2017, porque la gente no entiende de qué se trata la computación, piensan que la tienen en el iPhone, y esa ilusión es tan mala como la ilusión de que «Guitar Hero es igual que una guitarra real».

Kays .. guitarra real isn.t el CLI no exactamente. Hablaba de formas de programar computadoras que ofrecen el poder del CLI y que trascienden el software de escritura en archivos de texto. Existe la creencia entre los discípulos de Kays de que necesitamos salir de un máximo local basado en un texto en el que hemos estado viviendo durante décadas.

Es emocionante imaginar un futuro donde programamos computadoras de manera muy diferente. Incluso hoy en día, las hojas de cálculo son, con mucho, el lenguaje de programación más popular, y el movimiento sin código está despegar rápidamente mientras intenta reemplazar parte de la intensa demanda de programadores talentosos.

Sin embargo, con sus limitaciones crujidas y de décadas y peculiaridades inexplicables, la línea de comandos sigue siendo el rincón más versátil de la computadora. Te permite tirar de la cortina, ver lo que realmente está pasando, e interactúas creativamente con la máquina a un nivel de sofisticación y profundidad que las GUIs no pueden permitirse. Está disponible en casi cualquier laptop, para cualquiera que quiera aprenderlo. Se puede utilizar interactivamente, o se puede automatizar. Y, no cambia tan rápido como otras partes del sistema. Hay un valor creativo en su estabilidad.

Así que, aunque todavía lo tenemos, debemos tratar de maximizar su utilidad y accesibilidad.

Mucho ha cambiado sobre cómo programamos computadoras desde esos primeros días. La línea de comandos del pasado era la máquina-primero: poco más que un REPL en la parte superior de una plataforma de scripting. Pero a medida que los lenguajes interpretados por el uso general han florecido, el papel del guión de la concha se ha reducido. La línea de comandos de hoy es humana-primera : una interfaz de usuario basada en texto que permite el acceso a todo tipo de herramientas, sistemas y plataformas. En el pasado, el editor estaba dentro del terminal hoy, el terminal es igual de a menudo una característica del editor. Y hubo una proliferación de git-como comandos multiherramienta. Comandos dentro de comandos, y comandos de alto nivel que realizan flujos enteros en lugar de funciones atómicas.

Inspirados en la filosofía tradicional UNIX, impulsada por el interés de fomentar un entorno CLI más encantador y accesible, y guiados por nuestras experiencias como programadores, decidimos que era hora de revisar las mejores prácticas y los principios de diseño para construir programas de línea de comando.

Viva la línea de comandos.

Introducción

Este documento cubre tanto la filosofía de diseño de alto nivel como directrices concretas. Es más pesado en las directrices porque nuestra filosofía como practicantes no es filosofar demasiado. Creemos en el aprendizaje con el ejemplo, así que hemos proporcionado muchas de esas.

Esta guía no cubre programas terminales de pantalla completa como emacs y vim. Los programas de pantalla completa son proyectos de nicho.Muy pocos de nosotros estaremos en la posición de diseñar uno.

Esta guía también es agnóstica sobre los lenguajes de programación y el juego de herramientas en general.

Para quién es esta guía?

  • Si estás creando un programa CLI y estás buscando principios y prácticas concretas para su diseño de IU, esta guía es para ti.
  • Si usted es un diseñador profesional de la interfaz de usuario de CLI, eso es increíble que nos encanta aprender de usted.
  • Si desea evitar errores evidentes de la variedad que van en contra de 40 años de convenciones de diseño CLI, esta guía es para usted.
  • Si quieres deleitar a la gente con tu buen diseño y ayuda útil de tu programa, esta guía es definitivamente para ti.
  • Si usted está creando un programa de GUI, esta guía no es para usted, aunque usted puede aprender algunos anti-patrones GUI si usted decide leerlo de todos modos.
  • Si está diseñando un puerto CLI inmersivo y de pantalla completa de Minecraft, esta guía no es para usted. (Pero no podemos esperar a verlo.)

Filosofía

Estos son los principios fundamentales del buen diseño CLI.

El primer diseño humano

Tradicionalmente, los comandos UNIX se escribían bajo la suposición de que iban a ser utilizados principalmente por otros programas. Tenían más en común con las funciones en un lenguaje de programación que con aplicaciones gráficas.

Hoy en día, a pesar de que muchos programas CLI son utilizados principalmente (o incluso exclusivamente) por los humanos, gran parte de su diseño de interacción todavía lleva el equipaje del pasado. Es hora de deshacerse de parte de este equipaje: si un comando va a ser utilizado principalmente por los humanos, primero debe ser diseñado para los humanos.

Piezas simples que trabajan juntas

Un principio básico de la filosofía original de UNIX es la idea de que los programas pequeños y simples con interfaces limpias se pueden combinar para construir sistemas más grandes. En lugar de cosas más y más características en esos programas, usted hace programas que son lo suficientemente modulares para ser recombinados según sea necesario.

En los viejos tiempos, las tuberías y los scripts de conchas jugaron un papel crucial en el proceso de composición de los programas juntos. Su papel podría haber disminuido con el surgimiento de lenguajes interpretados por propósitos generales, pero ciertamente no han desaparecido. Más información, automatización a gran escala en la forma de CI/CD, orquestación y gestión de configuración ha florecido. Hacer que los programas sean compostables es tan importante como siempre.

Afortunadamente, las convenciones establecidas desde hace mucho tiempo del entorno UNIX, diseñadas para este propósito exacto, todavía nos ayudan hoy en día. Estándar en/fuera/err, señales, códigos de salida y otros mecanismos aseguran que los diferentes programas hagan clic juntos bien. El texto simple basado en la línea es fácil de tuberar entre comandos. JSON, una invención mucho más reciente, nos permite más estructura cuando la necesitamos, y nos permite integrar más fácilmente las herramientas de línea de comandos con la web.

Sea cual sea el software que estés construyendo, puedes estar absolutamente seguro de que la gente lo usará de maneras que no anticipaste. Su software se convertirá en una parte de un sistema más grande.Su única opción es sobre si será una parte bien porta.

Lo más importante es que el diseño para la composibilidad no tiene por qué estar en desacuerdo con el diseño para los humanos primero. Gran parte del consejo de este documento es sobre cómo lograr ambas cosas.

Coherencia en los programas

Las convenciones de terminal se nos meten en los dedos. Tuvimos que pagar un costo inicial aprendiendo sobre la sintaxis de línea de comandos, banderas, variables ambientales y así, pero vale la pena en eficiencia a largo plazo… siempre y cuando los programas sean consistentes.

Siempre que sea posible, un CLI debería seguir patrones que ya existen. Eso es lo que hace CLIs intuitivo y adivinable; eso lo que hace a los usuarios eficientes.

Dicho esto, a veces la coherencia entra en conflicto con la facilidad de uso. Por ejemplo, muchos comandos UNIX establecidos desde hace mucho tiempo no producen mucha información por defecto, lo que puede causar confusión o preocupación para personas menos familiarizadas con la línea de comandos.

Cuando la siguiente convención comprometería la usabilidad de un programa, podría ser el momento de romper con ella, pero tal decisión debe ser torida con cuidado.

Decir (justo) suficiente

El terminal es un mundo de información pura. Usted podría argumentar que la información es la interfaz. y que, al igual que con cualquier interfaz, a menudo hay demasiado o muy poco de ella.

Un comando está diciendo muy poco cuando cuelga durante varios minutos y el usuario comienza a preguntarse si está roto. Un comando está diciendo demasiado cuando desborde páginas y páginas de salida de depuración, ahogando lo que es verdaderamente importante en un océano de detritus suelto. El resultado final es el mismo: falta de claridad, dejando al usuario confundido e irritado.

Puede ser muy difícil hacer bien este equilibrio, pero es absolutamente crucial si el software es empoderar y servir a sus usuarios.

Facilo de descubrimiento

Cuando se trata de hacer que la funcionalidad sea descubrible, las GUIs tienen la ventaja. Todo lo que puedes hacer está colocado frente a ti en la pantalla, para que puedas encontrar lo que necesitas sin tener que aprender nada, y tal vez incluso descubrir cosas que no sabías que eran posibles.

Se supone que las interfaces de línea de comandos son lo opuesto a esto, que tienes que recordar cómo hacer todo. Las Directrices de Interfaz Humana de original, publicadas en 1987, recomiendan «Ver y punto» (en lugar de recordar-y-tipo) – como si sólo pudieras elegir uno u otro.

Estas cosas necesitan ser mutuamente excluyentes. La eficiencia de usar la línea de comandos viene de recordar los comandos, pero no hay razón para que los comandos puedan ayudarte a aprender y recordar.

Los CLIs descubribles tienen textos de ayuda completos, proporcionan muchos ejemplos, sugieren qué comando ejecutar a continuación, sugieren qué hacer cuando hay un error. Hay un montón de ideas que se pueden robar de GUIs para hacer CLIs más fácil de aprender y usar, incluso para los usuarios de energía.

Citación: El diseño de las cosas cotidianas (Don Norman), Macintosh Directrices de interfaz humana

La conversación como norma

El diseño GUI, particularmente en sus primeros días, hizo un uso pesado de la metáfora: escritorios, archivos, carpetas, contenedores de reciclaje. Tenía mucho sentido, porque las computadoras todavía estaban tratando de meterse en legitimidad. La facilidad de implementación de metáforas fue una de las enormes ventajas que las GUIs bateadas sobre CLIs. Irónicamente, sin embargo, el CLI ha encarnado una metáfora accidental todo el tiempo: es una conversación.

Más allá de los comandos más simples, ejecutar un programa por lo general implica más de una invocación. Por lo general, esto se debe a que es difícil hacerlo bien la primera vez: el usuario escribe un comando, obtiene un error, cambia el comando, obtiene un error diferente, y así sea, hasta que funciona. Este modo de aprendizaje a través de un fracaso repetido es como una conversación que el usuario está teniendo con el programa.

El juicio y el error no es el único tipo de interacción conversacional, sin embargo. Hay otros:

  • Ejecutar un comando para configurar una herramienta y luego aprender qué comandos ejecutar para empezar a usarlo realmente.
  • Ejecutar varios comandos para establecer una operación, y luego un comando final para ejecutarlo (por ejemplo, múltiples git adds, seguido de un git commit).
  • Explorando un sistema, por ejemplo, haciendo un montón de cdy lspara tener una idea de una estructura de directorio, o git logy git showexplorar la historia de un archivo.
  • Haciendo una seca de una operación compleja antes de ejecutarla de verdad.

Reconocer la naturaleza conversacional de la interacción de la línea de comandos significa que puedes llevar técnicas relevantes en su diseño. Puede sugerir posibles correcciones cuando la entrada del usuario no es válida, puede dejar claro el estado intermedio cuando el usuario está pasando por un proceso de varios pasos, puede confirmarles que todo se ve bien antes de hacer algo aterrador.

El usuario está conversando con su software, lo pretenda o no. En el peor de los casos, es una conversación hostil que los hace sentir estúpidos y resentidos. En el mejor de los casos, es un agradable intercambio que les acelera en su camino con un conocimiento recién encontrado y una sensación de logro.

Lectura adicional: La interfaz de usuario antimacoal (Don Gentner y Jakob Nielsen)

Robustez

La robustez es tanto una propiedad objetiva como subjetiva. El software debe ser robusto, por supuesto: la entrada inesperada debe manejarse con gracia, las operaciones deben ser idempotentes cuando sea posible, y así decir. Pero también debería sentirse robusto.

Quieres que tu software sienta que no se va a desmoronar. Quieres que se sienta inmediato y sensible, como si fuera una gran máquina mecánica, no un interruptor de plástico endeble.

La robustez subjetiva requiere atención al detalle y pensando mucho en lo que puede salir mal. Es un montón de pequeñas cosas: mantener informado al usuario sobre lo que está sucediendo, explicando lo que significan los errores comunes, no imprimir rastros de pila de aspecto aterrador.

Como regla general, la robustez también puede venir de mantenerla simple. Muchos casos especiales y código complejo tienden a hacer un programa frágil.

Empatía

Las herramientas de línea de comandos son un programador de herramientas creativas, por lo que deben ser agradables de usar. Esto no significa convertirlos en un videojuego, o usar un montón de emojis (aunque no hay nada inherentemente malo con el emoji). Significa darle al usuario la sensación de que estás de su lado, que quieres que tengan éxito, que hayas pensado cuidadosamente sobre sus problemas y cómo resolverlos.

No hay una lista de acciones que puedas tomar que se sientan así, aunque esperamos que siguiendo nuestro consejo te lleve un poco del camino allí. Deleitar al usuario significa superar sus expectativas a cada paso, y eso empieza con empatía.

Chaos

El mundo de la terminal es un desastre. Las incoherencias están por todas partes, ralentizarnos y haciéndonos adiórnos a nosotros mismos.

Sin embargo, es innegable que este caos ha sido una fuente de poder. El terminal, al igual que el entorno de computación de la UNIX en general, establece muy pocas restricciones en lo que se puede construir. En ese espacio, todo tipo de invención ha florecido.

Es irónico que este documento le implore que siga los patrones existentes, junto con un consejo que contradice décadas de tradición de línea de mando. Somos tan culpables de romper las reglas como cualquiera.

Puede llegar el momento en que tú también tengas que romper las reglas. Hazlo con intención y claridad de propósito.

Abanda a un estándar cuando es demostrablemente dañino para la productividad o la satisfacción del usuario. Jef Raskin, la interfaz humana

Directrices

Esta es una colección de cosas específicas que puedes hacer para mejorar tu programa de línea de comandos.

La primera sección contiene las cosas esenciales que necesitas seguir. Enséen esto mal, y su programa será difícil de usar o un mal ciudadano CLI.

El resto son agradables para amargar. Si tienes el tiempo y la energía para agregar estas cosas, tu programa será mucho mejor que el programa promedio.

La idea es que, si no quieres pensar demasiado en el diseño de tu programa, no tienes que: solo sigues estas reglas y tu programa probablemente será bueno. Por otro lado, si lo has pensado y determinaste que una regla está equivocada para tu programa, está bien. (No hay autoridad central que rechazará su programa por no seguir reglas arbitrarias.)

También estas reglas no están escritas en piedra. Si no está de acuerdo con una regla general por una buena razón, esperamos que proponga un cambio.

Lo básico

Hay algunas reglas básicas que necesitas seguir. Enséen esto, y su programa será muy difícil de usar, o roto de plano.

Utiliza una biblioteca de discusión de línea de comandos donde puedas. O su idioma integrado, o uno de terceros. Normalmente manejarán argumentos, análisis de banderas, texto de ayuda e incluso deletremos sugerencias de una manera sensata.

Estos son algunos que nos gustan:

Devuelve cero código de salida en el éxito, no-cero en el fracaso. Los códigos de salida son como los scripts determinan si un programa tuvo éxito o falló, por lo que debe informar esto correctamente. Mapa los códigos de salida no cero a los modos de falla más importantes.

Enviar salida a stdout. La salida principal para su comando debe ir a stdout. Cualquier cosa que sea legible máquina también debería ir stdoutAquí es donde la tubería envía las cosas por defecto.

Enviar mensajes a stderr. Los mensajes de registro, errores, etc. deben ser enviados a stderr. Esto significa que cuando los comandos se entuban juntos, estos mensajes se muestran al usuario y no se alimentan en el siguiente comando.

Ayuda

Mostrar el texto de ayuda cuando no se haya aprobado ninguna opción, el -hbandera, o la --help– bandera.

Mostrar un texto de ayuda conciso por defecto. Si puede, muestre ayuda por defecto cuando myappo o myapp subcommandestá corrido. A menos que su programa sea muy simple y haga algo obvio por defecto (por ejemplo. ls), o su programa lee entrada interactivamente (por ejemplo. cat).

El texto de ayuda conciso debe incluir únicamente:

  • Una descripción de lo que hace tu programa.
  • Una o dos invocaciones de ejemplo.
  • Descripciones de banderas, a menos que haya muchas de ellas.
  • Una instrucción para pasar el --helpBandera para más información.

jqlo hace bien. Cuando escribes jq, muestra una descripción introductoria y un ejemplo, luego le pide pasar jq --helppara la lista completa de las banderas:

$ jq
jq - commandline JSON processor [version 1.6]

Usage:    jq [options] <jq filter> [file...]
    jq [options] --args <jq filter> [strings...]
    jq [options] --jsonargs <jq filter> [JSON_TEXTS...]

jq is a tool for processing JSON inputs, applying the given filter to
its JSON text inputs and producing the filter's results as JSON on
standard output.

The simplest filter is ., which copies jq's input to its output
unmodified (except for formatting, but note that IEEE754 is used
for number representation internally, with all that that implies).

For more advanced filters see the jq(1) manpage ("man jq")
and/or https://stedolan.github.io/jq

Example:

    $ echo '{"foo": 0}' | jq .
    {
        "foo": 0
    }

For a listing of options, use jq --help.

Mostrar ayuda completa cuando -hy --helpha pasado. Todos ellos deberían mostrar ayuda:

$ myapp
$ myapp --help
$ myapp -h

Ignora cualquier otra bandera y argumentos que se pasen. -hal final de cualquier cosa y debería mostrar ayuda. No sobrecargar -h.

Si tu programa es git-como si fuera, lo siguiente también debería ofrecer ayuda:

$ myapp help
$ myapp help subcommand
$ myapp subcommand --help
$ myapp subcommand -h

Proporcionar una vía de apoyo para retroalimentación y cuestiones. Un sitio web o enlace de GitHub en el texto de ayuda de alto nivel es común.

En texto de ayuda, enlace a la versión web de la documentación. Si tiene una página específica o un anclaje para un subcomando, enlace directamente con eso. Esto es particularmente útil si hay documentación más detallada en la web, o lectura adicional que podría explicar el comportamiento de algo.

Dirición con ejemplos. Los usuarios tienden a utilizar ejemplos sobre otras formas de documentación, así que muébanlos primero en la página de ayuda, particularmente los usos complejos comunes. Si ayuda a explicar lo que hace y no es demasiado largo, muestra la salida real también.

Puedes contar una historia con una serie de ejemplos, construyendo tu camino hacia usos complejos.

Si tienes un montón de ejemplos, ponlos en otro lugar, en un comando de hoja de trampa o una página web. Es útil tener ejemplos exhaustivos y avanzados, pero no quieres hacer que tu ayuda sea realmente largo.

Para casos de uso más complejos, por ejemplo, cuando se integría con otra herramienta, podría ser apropiado escribir un tutorial en toda regla.

Mostrar las banderas y comandos más comunes al inicio del texto de ayuda. Está bien tener muchas banderas, pero si tienes algunas realmente comunes, exhibelas primero. Por ejemplo, el comando Git muestra los comandos para empezar y los subcomandos más comúnmente utilizados primero:

$ git
usage: git [--version] [--help] [-C <path>] [-c <name>=<value>]
           [--exec-path[=<path>]] [--html-path] [--man-path] [--info-path]
           [-p | --paginate | -P | --no-pager] [--no-replace-objects] [--bare]
           [--git-dir=<path>] [--work-tree=<path>] [--namespace=<name>]
           <command> [<args>]

These are common Git commands used in various situations:

start a working area (see also: git help tutorial)
   clone      Clone a repository into a new directory
   init       Create an empty Git repository or reinitialize an existing one

work on the current change (see also: git help everyday)
   add        Add file contents to the index
   mv         Move or rename a file, a directory, or a symlink
   reset      Reset current HEAD to the specified state
   rm         Remove files from the working tree and from the index

examine the history and state (see also: git help revisions)
   bisect     Use binary search to find the commit that introduced a bug
   grep       Print lines matching a pattern
   log        Show commit logs
   show       Show various types of objects
   status     Show the working tree status
…

Utilícese el formato en su texto de ayuda. Los audazles hacen que sea mucho más fácil escanear. Pero, trate de hacerlo de una manera independiente del terminal para que sus usuarios no estén mirando hacia abajo una pared de caracteres de escape.


$ heroku apps --help
list your apps

USAGE
  $ heroku apps

OPTIONS
  -A, --all          include apps in all teams
  -p, --personal     list apps in personal account when a default team is set
  -s, --space=space  filter by space
  -t, --team=team    team to use
  --json             output in json format

EXAMPLES
  $ heroku apps
  === My Apps
  example
  example2

  === Collaborated Apps
  theirapp   other@owner.name

COMMANDS
  apps:create     creates a new app
  apps:destroy    permanently destroy an app
  apps:errors     view app errors
  apps:favorites  list favorited apps
  apps:info       show detailed app information
  apps:join       add yourself to a team app
  apps:leave      remove yourself from a team app
  apps:lock       prevent team members from joining an app
  apps:open       open the app in a web browser
  apps:rename     rename an app
  apps:stacks     show the list of available stacks
  apps:transfer   transfer applications to another user or team
  apps:unlock     unlock an app so any team member can join

Nota: Cuando heroku apps --helpes canalizado a través de un buscapersonas, el comando no emite caracteres de escape.

Si el usuario hizo algo mal y puedes adivinar lo que quisieron decir, indínlo. Por ejemplo, brew update jqTe dice que deberías correr. brew upgrade jq.

Puedes preguntar si quieren ejecutar el comando sugerido, pero no lo forzaras en ellos. Por ejemplo:

$ heroku pss
 ›   Warning: pss is not a heroku command.
Did you mean ps? [y/n]:

En lugar de sugerir la sintaxis corregida, podrías estar tentado a ejecutarlo para ellos, como si lo hubieran escrito en primer lugar. A veces esto es lo correcto, pero no siempre.

En primer lugar, la entrada inválida no implica necesariamente un simple error de tipópolo a menudo puede significar que el usuario ha cometido un error lógico, o ha abusado de una variable de shell. Suponiendo lo que quisieron puede ser peligroso, especialmente si la acción resultante modifica el estado.

En segundo lugar, tenga en cuenta que si cambias lo que el usuario mecanografió, no aprenderá la sintaxis correcta. En efecto, usted está dictando que la forma en que lo escribieron es válida y correcta, y usted se compromete a apoyar eso indefinidamente. Sea intencional al tomar esa decisión, y documente ambas sintaxis.

Lea más: Haz lo que quiero decir.

Si su comando espera tener algo canalizado a él y stdines un terminal interactivo, mostrar ayuda inmediatamente y dejarlo. Esto significa que no cuelga, como cat. Alternativamente, usted podría imprimir un mensaje de registro a stderr.

Documentación

El propósito del texto de ayuda es dar un breve e inmediato sentido de cuál es su herramienta, qué opciones están disponibles y cómo realizar las tareas más comunes. La documentación, por otro lado, es donde entras en todo detalle. Es donde la gente va a entender para qué es su herramienta, para qué sirve, cómo funciona y cómo hacer todo lo que pueda necesitar hacer.

Proporcionar documentación basada en la web. La gente necesita ser capaz de buscar en línea para su documentación de herramientas, y para vincular a otras personas a partes específicas. La web es el formato de documentación más inclusivo disponible.

Proporcionar documentación en terminales. La documentación en el terminal tiene varias propiedades agradables: es de acceso rápido, se mantiene en sincronía con la versión específica instalada de la herramienta, y funciona sin conexión a Internet.

Considere la provisión de páginas de hombres. páginas de hombre, el sistema original de documentación de Unix, todavía están en uso hoy en día, y muchos usuarios comprobarán reflexivamente man mycmdcomo primer paso cuando se trata de aprender sobre tu herramienta. Para que sean más fáciles de generar, puedes usar una herramienta como ronn (que también puede generar tus documentos web).

Sin embargo, no todo el mundo lo sabe. man, y no se ejecuta en todas las plataformas, por lo que también debe asegurarse de que sus documentos de terminal son accesibles a través de su propia herramienta. Por ejemplo, gity npmhacer sus páginas de hombre accesibles a través de la helpsubcomando, así que npm help lses equivalente a man npm-ls.

NPM-LS(1)                                                            NPM-LS(1)

NAME
       npm-ls - List installed packages

SYNOPSIS
         npm ls [[<@scope>/]<pkg> ...]

         aliases: list, la, ll

DESCRIPTION
       This command will print to stdout all the versions of packages that are
       installed, as well as their dependencies, in a tree-structure.

       ...

Producto

La producción legible por el hombre es primordial. Los humanos vienen primero, las máquinas en segundo lugar. La heurística más simple y directa para saber si un flujo de salida en particular ( stdouto o stderr) está siendo leído por un humano es si es o no un TIT. Sea cual sea el lenguaje que estés usando, tendrá una utilidad o biblioteca para hacer esto (por ejemplo. Python, Node, Go).

Lectura más sobre lo que es un TTY.

Tener salida legible por máquina donde no tenga impacto en la usabilidad. Corridas de texto es la interfaz universal en UNIX. Los programas típicamente las líneas de salida de texto, y los programas típicamente esperan líneas de texto como entrada, por lo tanto se puede componer varios programas juntos. Esto se hace normalmente para que sea posible escribir guiones, pero también puede ayudar a la usabilidad de los humanos usando programas. Por ejemplo, un usuario debe ser capaz de canalizar la salida a grepy debería hacer lo que ellos esperan.

Espere la salida de cada programa para convertirse en la entrada a otro programa, aún desconocido. Doug McIlroy

Si la salida legible por la persona romper la salida legible por máquina, utilice --plainpara mostrar la salida en formato de texto sencillo y tabular para la integración con herramientas como grepo o awk. En algunos casos, es posible que necesites producir información de una manera diferente para hacerlo legible por humanos.

Por ejemplo, si usted está mostrando una tabla basada en línea, es posible que elija dividir una celda en varias líneas, encajándola en más información mientras la mantiene dentro de la anchura de la pantalla. Esto romper el comportamiento esperado de haber un pedazo de datos por línea, por lo que debe proporcionar un --plainBandera para scripts, que deshabilita toda dicha manipulación y salidas un récord por línea.

Exipidad de visualización como JSON formateado si --jsonha pasado. JSON permite más estructura que el texto plano, por lo que hace mucho más fácil la salida y el manejo de estructuras de datos complejas. jqes una herramienta común para trabajar con JSON en la línea de comandos, y ahora hay todo un ecosistema de herramientas que se desbanca y manipulan JSON.

También se utiliza ampliamente en la web, por lo que al utilizar JSON como la entrada y salida de programas, puede canalizar directamente desde y hacia los servicios web utilizando curl.

Mostrar la salida sobre el éxito, pero mantenlo breve. Tradicionalmente, cuando nada está mal, los comandos UNIX no muestran salida al usuario. Esto tiene sentido cuando se utilizan en los scripts, pero pueden hacer que los comandos parezcan estar colgando o roto cuando son usados por los humanos. Por ejemplo, cpno imprimirá nada, aunque lleve mucho tiempo.

Es raro que no imprimir nada en absoluto es el mejor comportamiento por defecto, pero por lo general es mejor errar en el lado de menos.

Para los casos en los que no desea salida (por ejemplo, cuando se utiliza en scripts de shell), para evitar la torpe redirección de stderra /dev/null, usted puede proporcionar un -qopción para suprimir toda salida no esencial.

Si cambia de estado, díselo al usuario. Cuando un comando cambia el estado de un sistema, es especialmente valioso para explicar lo que acaba de suceder, por lo que el usuario puede modelar el estado del sistema en su cabeza, especialmente si el resultado no mapea directamente a lo que el usuario solicitó.

Por ejemplo, git pushTe dice exactamente lo que está haciendo, y cuál es el nuevo estado de la remota rama:

$ git push
Enumerating objects: 18, done.
Counting objects: 100% (18/18), done.
Delta compression using up to 8 threads
Compressing objects: 100% (10/10), done.
Writing objects: 100% (10/10), 2.09 KiB | 2.09 MiB/s, done.
Total 10 (delta 8), reused 0 (delta 0), pack-reused 0
remote: Resolving deltas: 100% (8/8), completed with 8 local objects.
To github.com:replicate/replicate.git
 + 6c22c90...a2a5217 bfirsh/fix-delete -> bfirsh/fix-delete

Haz que sea fácil ver el estado actual del sistema. Si su programa hace un montón de cambios de estado complejos y no es inmediatamente visible en el sistema de archivos, asegúrese de hacer esto fácil de ver.

Por ejemplo, git statusle indica tanta información como sea posible sobre el estado actual de su repositorio de Git, y algunas pistas sobre cómo modificar el estado:

$ git status
On branch bfirsh/fix-delete
Your branch is up to date with 'origin/bfirsh/fix-delete'.

Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git restore <file>..." to discard changes in working directory)
	modified:   cli/pkg/cli/rm.go

no changes added to commit (use "git add" and/or "git commit -a")

Sugerir los comandos que el usuario debe ejecutar. Cuando varios comandos forman un flujo de trabajo, sugiriendo a los comandos de usuario que pueden ejecutar a continuación les ayuda a aprender cómo usar su programa y descubrir nuevas funcionalidades. Por ejemplo, en la git statussalidas por encima, sugiere comandos que puedes ejecutar para modificar el estado que estás viendo.

Las acciones que cruzan la frontera del mundo interno del programa deben ser generalmente explícitas. Esto incluye cosas como:

  • Leer o escribir archivos que el usuario no pasar explícitamente como argumentos (a menos que esos archivos estén almacenando el estado del programa interno, como una caché).
  • Hablando con un servidor remoto, por ejemplo, para descargar un archivo.

Aumentar la densidad de la información con ASCII art. Por ejemplo, lsmuestra permisos de una manera escaneable. Cuando lo veas por primera vez, puedes ignorar la mayor parte de la información. Luego, a medida que aprendes cómo funciona, eliges más patrones con el tiempo.

-rw-r--r-- 1 root root     68 Aug 22 23:20 resolv.conf
lrwxrwxrwx 1 root root     13 Mar 14 20:24 rmt -> /usr/sbin/rmt
drwxr-xr-x 4 root root   4.0K Jul 20 14:51 security
drwxr-xr-x 2 root root   4.0K Jul 20 14:53 selinux
-rw-r----- 1 root shadow  501 Jul 20 14:44 shadow
-rw-r--r-- 1 root root    116 Jul 20 14:43 shells
drwxr-xr-x 2 root root   4.0K Jul 20 14:57 skel
-rw-r--r-- 1 root root      0 Jul 20 14:43 subgid
-rw-r--r-- 1 root root      0 Jul 20 14:43 subuid

Utilice el color con la intención. Por ejemplo, es posible que desee destacar algún texto para que el usuario lo note, o use rojo para indicar un error. No lo desgaste en exceso.Si todo es un color diferente, entonces el color no significa nada y sólo hace que sea más difícil de leer.

Desactiva color si tu programa no está en un terminal o el usuario lo solicitó. Estas cosas deben desactivar los colores:

  • stdouto o stderrno es un terminal interactivo (un TTY). Es mejor comprobarlo individualmente. stdouta otro programa, todavía es útil para conseguir colores en stderr.
  • El NO_COLORvariable de entorno se establece.
  • El TERMla variable de entorno tiene el valor dumb.
  • El usuario pasa la opción --no-color.
  • También puede que desee añadir un MYAPP_NO_COLORvariable de entorno en caso de que los usuarios quieran desactivar el color específicamente para su programa.

Lectura adicional: no-color.org, 12 Factor CLI Apps

Si stdoutno es un terminal interactivo, no mostrar ninguna animación. Esto impedirá el progreso de las barras que se convierten en árboles de Navidad en la salida de registro de CI.

Utiliza símbolos y emojis donde haga las cosas más claras. Las fotos pueden ser mejores que las palabras si necesitas hacer varias cosas distintas, captar la atención del usuario, o simplemente añadir un poco de carácter. Tenga cuidado, aunque puede ser fácil exagerar y hacer que su programa se vea desordenado o se siente como un juguete.

Por ejemplo, el agente de yubikey usa emoji para añadir estructura a la salida para que no sea sólo una pared de texto, y un » para llamar su atención sobre una importante pieza de información:

$ yubikey-agent -setup
🔐 The PIN is up to 8 numbers, letters, or symbols. Not just numbers!
❌ The key will be lost if the PIN and PUK are locked after 3 incorrect tries.

Choose a new PIN/PUK: 
Repeat the PIN/PUK: 

🧪 Retriculating splines …

✅ Done! This YubiKey is secured and ready to go.
🤏 When the YubiKey blinks, touch it to authorize the login.

🔑 Here's your new shiny SSH public key:
ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBCEJ/
UwlHnUFXgENO3ifPZd8zoSKMxESxxot4tMgvfXjmRp5G3BGrAnonncE7Aj11pn3SSYgEcrrn2sMyLGpVS0=

💭 Remember: everything breaks, have a backup plan for when this YubiKey does.

Por defecto, no información de salida que sólo sea comprensible por los creadores del software. Si una pieza de salida sirve sólo para ayudarle (el desarrollador) a entender lo que su software está haciendo, casi con seguridad no debería mostrarse a los usuarios normales por defecto.

Invite retroalimentación de usabilidad de extraños y personas que son nuevas en su proyecto. Te ayudarán a ver temas importantes que estás demasiado cerca del código para notarlo.

No trates stderrcomo un archivo de registro, al menos no por defecto. No imprimir etiquetas de nivel de registro (ERR, WARN, etc.) o información contextual extraña, a menos que en modo verboso.

Utilícele un buscapersonas (por ejemplo. less) si está produciendo mucho texto. Por ejemplo, git diffhace esto por defecto. El uso de un buscapersonas puede ser propenso a errores, así que ten cuidado con tu implementación de tal manera que no empeore la experiencia para el usuario. No deberías usar un buscapersonas si stdino o stdoutno es un terminal interactivo.

Un buen conjunto sensato de opciones para lesses less -FIRX. Esto no página si el contenido llena una pantalla, ignora el caso cuando busca, permite el color y el formato, y deja el contenido en la pantalla cuando less– Renja.

Puede haber bibliotecas en su idioma que sean más robustas que tuberías a less. Por ejemplo, pypager en Python.

Errores

Una de las razones más comunes para consultar la documentación es arreglar errores. Si puede cometer errores en la documentación, esto le ahorrará el tiempo al usuario.

Atrapa los errores y reescribirlos para los humanos. Si esperas que ocurra un error, cómpralo y reescribe el mensaje de error para ser útil. Piense en ello como una conversación, donde el usuario ha hecho algo malo y el programa los está guiando en la dirección correcta. Ejemplo: Escriba a file.txt. Usted puede necesitar hacerlo escrito ejecutando el sitio de «chmod file.txt».

La relación señal-ruido es crucial. Cuanto más relevante produzca la salida, más tiempo va a llevar al usuario a averiguar lo que hizo mal. Si su programa produce múltiples errores del mismo tipo, considere agruparlos bajo una sola cabecera explicativa en lugar de imprimir muchas líneas de aspecto similar.

Considere dónde buscará el usuario primero. Pon la información más importante al final de la salida. El ojo se dilatará al texto rojo, así que úsalo intencionalmente y con moderación.

Si hay un error inesperado o inexplicable, proporcione información de depuración y rastreo, e instrucciones sobre cómo enviar un error. Dicho esto, no se olvide de la relación señal-ruido: no quieres abruer al usuario con información que no entiende. Considere escribir el registro de depuración a un archivo en lugar de imprimirlo en el terminal.

Haz que sea fácil presentar informes de errores. Una buena cosa que puede hacer es proporcionar una URL y tenerla pre-poblando tanta información como sea posible.

Argumentos y banderas

Nota sobre la terminología:

  • Los argumentos, o args, son parámetros posicionales para un comando. Por ejemplo, las rutas de archivo que proporciona a cpson args. El orden de los args es a menudo importante: cp foo barsignifica algo diferente de cp bar foo.
  • Las banderas son nombradas parámetros, denotadas con un guión y un nombre de una sola letra (-r) o un guión doble y un nombre de letra múltiple (--recursive). Pueden o no incluir también un valor especificado por el usuario (--file foo.txt, o --file=foo.txt). El orden de las banderas, en general, no afecta la semántica del programa.

Prefiere las banderas a los args. Es un poco más de meclear, pero lo deja mucho más claro lo que está pasando. También facilita hacer cambios en la forma en que acepta la entrada en el futuro. A veces, cuando se utiliza args, es imposible añadir nuevas entradas sin romper el comportamiento existente o crear ambiguedad.

Citación: 12 Aplicaciones de Factor CLI.

Tener versiones completas de todas las banderas. Por ejemplo, ambos -hy --help. Tener la versión completa es útil en los guiones donde quieres ser verbierto y descriptivo, y no tienes que buscar el significado de las banderas por todas partes.

Citación: Normas de codificación de GNU.

Sólo use banderas de una letra para las banderas de uso común, particularmente en el nivel superior cuando use subcomandos. De esa manera no, tu espacio de nombres de banderas cortas, obligándote a usar letras y estuches enrevesados para las banderas que añades en el futuro.

Múltiples argumentos están bien para acciones simples contra varios archivos. Por ejemplo, rm file1.txt file2.txt file3.txt. Esto también hace que funcione con globbing: rm *.txt.

Si tienes dos o más argumentos para diferentes cosas, probablemente estás haciendo algo malo. La excepción es una acción común, primaria, donde la brevedad vale la pena memorizar. Por ejemplo, cp <source> <destination>.

Citación: 12 Aplicaciones de Factor CLI.

Utilíce nombres estándar para las banderas, si hay un estándar. Si otro comando comúnmente usado usa un nombre de bandera, es mejor seguir ese patrón existente. De esta manera, un usuario no tiene que recordar dos opciones diferentes (y a qué comando se aplica), e incluso los usuarios pueden adivinar una opción sin tener que mirar el texto de ayuda.

Aquí está una lista de opciones de uso común:

  • -a, --all– Todo. Por ejemplo, ps, fetchmail.
  • -d, --debug: Mostrar salida de depuración.
  • -f, --forceFuerza. Por ejemplo, rm -fforzará la eliminación de los archivos, incluso si cree que no tiene permiso para hacerlo. Esto también es útil para los comandos que están haciendo algo destructivo que normalmente requiere confirmación del usuario, pero usted quiere forzarlo a hacer esa acción destructiva en un script.
  • --json: Mostrar salida JSON. Vea la sección de salida.
  • -h, --helpAyuda. Esto sólo debería significar ayuda. Vea la sección de ayuda.
  • --no-input: Ver la sección de interactividad.
  • -o, --output: Archivo de salida. Por ejemplo, sort, gcc.
  • -p, --port: Port. Por ejemplo, psql, ssh.
  • -q, --quiet: Silamos. Mostrar menos salida. Esto es particularmente útil cuando se muestra la salida para los humanos que podrías querer ocultar cuando se ejecuta en un script.
  • -u, --userUsuario. Por ejemplo, ps, ssh.
  • --versionVersión.
  • -v: Esto a menudo puede significar verbose o versión. Tal vez quieras usar -dpara verbose y esto para la versión, o para nada para evitar confusiones.

Haz de la predeterminada lo correcto para la mayoría de los usuarios. Hacer las cosas configurables es bueno, pero la mayoría de los usuarios no van a encontrar la bandera adecuada y recuerda usarla todo el tiempo (o alias ella). Si no es el valor predeterminado, estás empeorando la experiencia para la mayoría de tus usuarios.

Por ejemplo, lstiene una salida predeterminada para optimizar para los scripts y otras razones históricas, pero si se diseñara hoy en día, probablemente sería predeterminado a ls -lhF.

Insótaque para la entrada del usuario. Si un usuario no pasa una discusión o bandera, inste por ello. (Véase también: Interactividad)

Nunca necesito un aviso. Proporte siempre una forma de pasar la entrada con banderas o argumentos. Si stdinno es un terminal interactivo, saltar la indicación y sólo requiere esas banderas/args.

Confirma antes de hacer algo peligroso. Una convención común es pedir que el usuario escriba yo o yessi se ejecuta interactivamente, o requiriendo que pasen -fo o --forcede otra manera.

Es un término subjetivo, y hay diferentes niveles de peligro:

  • Suave: Un pequeño cambio local como la eliminación de un archivo. Tal vez quieras pedir confirmación, puede que no. Por ejemplo, si el usuario está ejecutando explícitamente un comando llamado algo como «delete», probablemente no tengas que preguntar.
  • Moderado: Un cambio local más grande como la eliminación de un directorio, un cambio remoto como borrar un recurso de algún tipo, o una modificación a granel compleja que puede ser fácilmente deshecho. Normalmente quieres pedir confirmación aquí. Considere darle al usuario una manera de ejecutar secamente la operación para que pueda ver lo que sucederá antes de comprometerse con ella.
  • Severo: Suprimiendo algo complejo, como toda una aplicación remota o servidor. No sólo quieres pedir confirmación aquí. Quieres que sea difícil de confirmar por accidente. Considere pedirles que escriba algo no trivial, como el nombre de la eliminación. Que pasen una bandera como --confirm="name-of-thing", así que sigue siendo guionable.

Considere si hay maneras no obvias de destruir las cosas accidentalmente. Por ejemplo, imagine una situación en la que cambiar un número en un archivo de configuración de 10 a 1 significa que 9 cosas serán implícitamente eliminadas.Esto debe considerarse un riesgo severo, y debe ser difícil de hacer por accidente.

Si la entrada o salida es un archivo, soporte -a leer desde stdino escribir a stdout. Esto permite que la salida de otro comando sea la entrada de su comando y viceversa, sin usar un archivo temporal. Por ejemplo, tarpuede extraer archivos de stdin:

$ curl https://example.com/something.tar.gz | tar xvf -

Si una bandera puede aceptar un valor opcional, deje una palabra especial como la denone. Por ejemplo, ssh -Ftoma un nombre opcional de una alternativa ssh_configarchivo, y ssh -F noneejecuta SSH sin archivo de configuración. No utilices un valor en blanco.Esto puede hacer ambiguo si los argumentos son valores de bandera o argumentos.

Si es posible, haga argumentos, banderas y subcomandos queden independientes del orden. Muchos CLI, especialmente aquellos con subcomandos, tienen reglas táctiles sobre dónde se pueden presentar varios argumentos. Por ejemplo, un comando podría tener un --foobandera que sólo funciona si la pones ante el subcomando:

mycmd --foo=1 subcmd
works

$ mycmd subcmd --foo=1
unknown flag: --foo

Esto puede ser muy confuso para el usuario, especialmente teniendo en cuenta que una de las cosas más comunes que hacen los usuarios cuando se trata de conseguir un comando para trabajar es golpear la flecha para obtener la última invocación, pegar otra opción al final, y ejecutarlo de nuevo. Si es posible, trate de hacer ambas formas equivalentes, aunque usted podría toparse con las limitaciones de su parser argumental.

No leas secretos directamente de las banderas. Cuando un comando acepta un secreto, por ejemplo, a través de un --passwordargumento, el valor argumental filtrará el secreto en pssalida y potencialmente historial de conchas. Y, este tipo de banderas fomenta el uso de variables de ambiente inseguras para los secretos.

Considerar aceptar datos sensibles sólo a través de archivos, por ejemplo con un --password-fileargumento, o a través de stdin. A --password-fileEl argumento permite que un secreto se transmita discamente, en una amplia variedad de contextos.

(Es posible pasar un contenido de archivo en una discusión en Bash mediante el uso de --password $(< password.txt). Este enfoque tiene el mismo problema de seguridad de filtrar el contenido de archivo en la salida de ps. Es mejor evitarlo.)

Interactividad

Utilízse únicamente indicaciones o elementos interactivos si stdines un terminal interactivo (un TTY). Esta es una manera bastante confiable de saber si usted está entraando datos en un comando o si se ejecuta en un script, en cuyo caso un prompt won.t funciona y usted debe lanzar un error diciendo al usuario qué bandera pasar.

Si --no-inputse pasa, no nos avisen o hagan nada interactivo. Esto permite a los usuarios una manera explícita de desactivar todos los avisos en los comandos. Si el comando requiere entrada, falla y dílele al usuario cómo pasar la información como bandera.

Si usted está pidiendo una contraseña, no la imprima como los tipos de usuario. Esto se hace desactivando el eco en la terminal. Tu lenguaje debería tener ayudantes para esto.

Deje escapar al usuario. Que quede claro cómo salir. No hagas lo que hace vim.) Si su programa cuelga en la red de E/S, etc, haga que Ctrl-C siga funcionando. Si es un envoltorio en la ejecución del programa donde Ctrl-C puede deje de dejar de hacerlo (SSH, tmux, telnet, etc.), deje quede claro cómo hacerlo. Por ejemplo, SSH permite secuencias de escape con el ~El carácter de escape.

Subcomandos

Si tienes una herramienta que sea suficientemente compleja, puedes reducir su complejidad haciendo un conjunto de subcomandos. Si tienes varias herramientas que están muy estrechamente relacionadas, puedes hacerlas más fáciles de usar y descubrir combinándolas en un solo comando (por ejemplo, RCS vs. Git).

Son útiles para compartir cosas. banderas globales, texto de ayuda, configuración, mecanismos de almacenamiento.

Sé consistente en los subcomandos. Utiliza los mismos nombres de bandera para las mismas cosas, tienes formato de salida similar, etc.

Utilre nombres consistentes para múltiples niveles de subcomando. Si una pieza compleja de software tiene muchos objetos y operaciones que se pueden realizar en esos objetos, es un patrón común para usar dos niveles de subcomando para esto, donde uno es un sustantivo y uno es un verbo. Por ejemplo, docker container create. Sea consistente con los verbos que utilice a través de diferentes tipos de objetos.

O bien noun verbo o verb nounordenar obras, pero noun verbparece más común.

Lectura adicional: Experiencia de usuario, CLIs, y romper el mundo, por John Starich.

No tenga comandos ambiguos o de nombre similar. Por ejemplo, tener dos subcomandos llamados «actualización», y «upgrade», es bastante confuso. Es posible que desee usar diferentes palabras, o disambiguate con palabras extra.

Robustez

Validar la entrada del usuario. En todas partes que su programa acepte datos del usuario, eventualmente se les darán malos datos. Revise temprano y rescata antes de que algo malo suceda, y haga comprensibles los errores.

Responsivo es más importante que rápido. Imprime algo al usuario en 100ms. Si estás haciendo una solicitud de red, imprime algo antes de hacerlo para que no cuelgue y se vea roto.

Mostrar progreso si algo lleva mucho tiempo. Si su programa no muestra salida por un tiempo, se verá roto. Un buen spinner o indicador de progreso puede hacer que un programa parezca ser más rápido de lo que es.

Ubuntu 20.04 tiene una bonita barra de progreso que se pega al fondo de la terminal.

Si la barra de progreso se queda atascada en un lugar durante mucho tiempo, el usuario no sabrá si las cosas siguen sucediendo o si el programa se estrelló. Es bueno mostrar el tiempo estimado restante, o incluso tener un componente animado, para asegurarles que todavía estás trabajando en él.

Hay muchas buenas bibliotecas para generar barras de progreso. Por ejemplo, tqdm para Python, schollz/progressbar para Go, y nodos-progress para Node.js.

Haz cosas en paralelo donde puedas, pero sé reflexiva al respecto. Ya es difícil informar de los progresos en la cáscara; hacerlo para procesos paralelos es diez veces más difícil. Asegúrese de que sea robusto, y que la salida no esté confusamente interviada. Si puedes usar una biblioteca, hazlo.Este es el código que no quieres escribirte a ti mismo. Bibliotecas como tqdm para Python y schollz/progressbar para Go apoyan múltiples barras de progreso nativamente.

La ventaja es que puede ser una enorme ganabilidad. Por ejemplo, docker pullLas múltiples barras de progreso ofrecen una visión crucial de lo que está pasando.

$ docker image pull ruby
Using default tag: latest
latest: Pulling from library/ruby
6c33745f49b4: Pull complete 
ef072fc32a84: Extracting [================================================>  ]  7.569MB/7.812MB
c0afb8e68e0b: Download complete 
d599c07d28e6: Download complete 
f2ecc74db11a: Downloading [=======================>                           ]  89.11MB/192.3MB
3568445c8bf2: Download complete 
b0efebc74f25: Downloading [===========================================>       ]  19.88MB/22.88MB
9cb1ba6838a0: Download complete 

Una cosa a tener en cuenta: esconder los registros detrás de las rejas de progreso cuando las cosas van bien hace que sea mucho más fácil para el usuario entender lo que está pasando, pero si hay un error, asegúrese de imprimir los registros. De lo contrario, será muy difícil de depurar.

Haz que las cosas pasen. Permite que los timeouts de la red sean configurados, y tengan un valor predeterminado razonable para que no se cuelgue para siempre.

Hazlo recuperable. Si el programa falla por alguna razón transitoria (por ejemplo, la conexión a Internet se apagó), usted debe ser capaz de golpear <up>y <enter>y debería retoir de donde lo dejó.

Que sea solo estrellado. Este es el siguiente paso de idempotencia. Si puede evitar la necesidad de hacer cualquier limpieza después de las operaciones, o puede aplazar esa limpieza para la siguiente carrera, su programa puede salir inmediatamente por falla o interrupción. Esto lo hace más robusto y más sensible.

Citación: Software solo para choque: Más de lo que parece.

La gente va a hacer mal uso de su programa. Estén preparados para eso. Lo envolverán en scripts, lo usarán en malas conexiones a Internet, ejecutarán muchos casos de ella a la vez, y lo usarán en entornos en los que has probado, con peculiaridades en las que no anticipaste. (Sabías que macOS filesystems son insensibles a los casos, pero también a la conservación de casos?)

A prueba de futuro

En un software de cualquier tipo, es crucial que las interfaces no cambien sin un proceso de deprecación largo y bien documentado. Subcomandos, argumentos, banderas, archivos de configuración, variables de entorno: todas estas son interfaces, y te comprometes a mantenerlos funcionando. (La versión semántica sólo puede excusar tanto cambio; si usted está poniendo un golpe de versión principal cada mes, no tiene sentido.)

Mantenga los cambios aditivo donde pueda. En lugar de modificar el comportamiento de una bandera de una manera incompatible hacia atrás, tal vez usted puede añadir una nueva bandera siempre y cuando no hiere la interfaz demasiado. (Véase también: Prefiere banderas a args.)

Advide antes de hacer un cambio no aditivo. Eventualmente, encontrarás que no puedes evitar romper una interfaz. Antes de hacerlo, adviento a sus usuarios en el propio programa: cuando pasen la bandera que está buscando despretar, dígales que se va a cambiar pronto. Asegúrese de que una manera de que puedan modificar su uso hoy para hacerlo a prueba de futuro, y decirles cómo hacerlo.

Si es posible, usted debe detectar cuando ellos han cambiado su uso y no mostrar más la advertencia: ahora no notan nada cuando finalmente despliegue el cambio.

Cambiar la salida para los seres humanos suele estar bien. La única manera de hacer una interfaz fácil de usar es iterar en ella, y si la salida se considera una interfaz, entonces no puede iterar en ella. Anime a sus usuarios a usar --plaino o --jsonen scripts para mantener la salida estable (ver Salida).

No tengas un subcomando. Si usted tiene un subcomando que probablemente sea el más utilizado, usted podría estar tentado a dejar que la gente lo omita completamente por el bien de la brevedad. Por ejemplo, digamos que tienes un runcomando que envuelve un comando arbitrario de shell:

$ mycmd run echo "hello world"

Podrías hacerlo para que si el primer argumento a mycmdes el nombre de un subcomando existente, usted asume los medios de usuario run, para que puedan escribir esto:

$ mycmd echo "hello world"

Esto tiene un inconveniente serio, sin embargo: ahora nunca se puede añadir un subcomando nombrado echo-o cualquier cosa sin arriesgarse a romper los usos existentes. Si hay un guión por ahí que usa mycmd echo, hará algo completamente diferente después de que el usuario actualice a la nueva versión de su herramienta.

No permita abreviaturas arbitrarias de subcomandos. Por ejemplo, digamos que su comando tiene un installsubcomando. Cuando lo añadiste, querías ahorrar a los usuarios algún tipo de mecanografiado, así que les permitiste escribir cualquier prefijo no ambiguo, como mycmd ins, o incluso sólo mycmd i, y que sea un alias para mycmd install. Ahora estás atascado: no puedes añadir más comandos que comiencen con i, porque hay guiones por ahí que asumen ilos medios install.

No hay nada malo con alias.saving en escribir es bueno, pero deberían ser explícitos y permanecer estables.

No crees una bomba de tiempo. Imagínate dentro de 20 años. Su comando seguirá corrido igual que hoy en día, o dejará de funcionar porque alguna dependencia externa de internet ha cambiado o ya no se mantiene? El servidor más propenso a no existir en 20 años es el que estás manteniendo en este momento. (Pero no se construya en una llamada de bloqueo a Google Analytics tampoco.)

Señales y caracteres de control

Si un usuario llega a Ctrl-C (la señal INT), sal lo antes posible. Di algo inmediatamente, antes de empezar a limpiar. Añade un tiempo de espera a cualquier código de limpieza para que no pueda colgar para siempre.

Si un usuario llega a Ctrl-C durante las operaciones de limpieza que podrían tomar mucho tiempo, olvídelos. Dile al usuario qué pasará cuando vuelva a Ctrl-C, en caso de que sea una acción destructiva.

Por ejemplo, al dejar de Docker Compose, puedes golpear Ctrl-C por segunda vez para forzar a tus contenedores a detenerse inmediatamente en lugar de cerrarlos con gracia.

$  docker-compose up
…
^CGracefully stopping... (press Ctrl+C again to force)

Su programa debe esperar que se inicie en una situación en la que no se ha llevado a la limpieza. (Ver software solo para choque: Más de lo que parece.)

Configuración

Las herramientas de línea de comandos tienen muchos tipos diferentes de configuración, y muchas maneras diferentes de suministrarlo (flags, variables de entorno, archivos de configuración a nivel de proyecto). La mejor manera de suministrar cada pieza de configuración depende de algunos factores, entre ellos la especificidad, estabilidad y complejidad.

La configuración generalmente se divide en algunas categorías:

  1. Es probable que varíe de una invocación del mando a otro.Ejemplos:
    • Ajuste del nivel de la producción de depuración
    • Habilitar un modo seguro o secado de un programa

    Recomendación: Utilícese banderas. Las variables de medio ambiente pueden o no ser útiles también.

  2. Generalmente estable de una invocación a la siguiente, pero no siempre. Podría variar entre proyectos. Definitivamente varía entre diferentes usuarios que trabajan en el mismo proyecto.Este tipo de configuración es a menudo específica de una computadora individual.

    Ejemplos:

    • Proporcionar una ruta no predeterminada a los elementos necesarios para que un programa comience
    • Especificando cómo o si el color debe aparecer en la salida
    • Especificar un servidor proxy HTTP para enlacer todas las solicitudes a través de

    Recomendación: Utiliza banderas y probablemente variables ambientales también. Los usuarios pueden querer establecer las variables en su perfil de shell para que se apliquen globalmente, o en .envpara un proyecto en particular.

    Si esta configuración es lo suficientemente compleja, puede garantizar un archivo de configuración propio, pero las variables de entorno suelen ser lo suficientemente buenas.

  3. Estable dentro de un proyecto, para todos los usuarios.Este es el tipo de configuración que pertenece al control de la versión. Archivos como Makefile, package.jsony docker-compose.ymlson todos ejemplos de esto.

    Recomendación: Utilícele un archivo específico de comandos y controlado con la versión.

Siga la especificación XDG. En 2010 el Grupo X Desktop, ahora freedesktop.org, desarrolló una especificación para la ubicación de los directorios básicos donde se pueden ubicar archivos de configuración. Uno de los objetivos era limitar la proliferación de puntos en un directorio de usuario apoyando un propósito general ~/.configla carpeta. La especificación XDG Base Directory (celebrada, resumen) está soportada por hilo, pescado, tiburón de alambre, emacs, neovim, tmux, y muchos otros proyectos que conoces y amas.

Si modifica automáticamente la configuración que no es su programa, pídele el consentimiento al usuario y dígale exactamente lo que hace. Prefiere crear un nuevo archivo de configuración (por ejemplo. /etc/cron.d/myapp) en lugar de adjuntar a un archivo de configuración existente (por ejemplo, /etc/crontab). Si tienes que adjuntar o modificarlo a un archivo de configuración en todo el sistema, usa un comentario fechado en ese archivo para delinear tus adiciones.

Aplicar parámetros de configuración en orden de precedencia. Aquí está la precedencia para los parámetros de configuración, de lo más alto a más bajo:

  • Banderas
  • Las variables de entorno de la concha en marcha
  • Configuración a nivel de proyecto (por ejemplo. .env)
  • Configuración a nivel de usuario
  • Configuración amplia del sistema

Variables de medio ambiente

Las variables ambientales son para un comportamiento que varía con el contexto en el que se ejecuta un comando. El medioambiental de una variable de entorno es la sesión terminal, el contexto en el que se ejecuta el comando. Por lo tanto, un env var podría cambiar cada vez que un comando funciona, o entre sesiones terminales en una máquina, o entre instantiaciones de un proyecto a través de varias máquinas.

Las variables de medio ambiente pueden duplicar la funcionalidad de las banderas o los parámetros de configuración, o pueden ser distintas de esas cosas. Consulte Configuración para un desglose de los tipos comunes de configuración y recomendaciones sobre cuándo las variables de entorno son más apropiadas.

Para la portabilidad máxima, los nombres de variables del medio ambiente solo deben contener letras mayúsculas, números y subrayados (y no empezar con un número). Lo que significa O_Oy OWOson los únicos emoticonos que también son nombres válidos de la variable de entorno.

Apunte a los valores de variables de entorno de una sola línea. Si bien los valores multilínea son posibles, crean problemas de usabilidad con la envcomando.

Evite comandar nombres ampliamente usados. Una lista de POSIX estándar env vars.

Comaee las variables de entorno de uso general para los valores de configuración cuando sea posible:

  • NO_COLOR, para desactivar el color (ver Salida)
  • DEBUG, para permitir más salida verbúse
  • EDITOR, si necesita pedir al usuario que edite un archivo o introducir más de una sola línea
  • HTTP_PROXY, HTTPS_PROXY, ALL_PROXYy NO_PROXY, si vas a realizar operaciones de red (La biblioteca HTTP que usas ya podrías comprobarlo.)
  • SHELL, si necesita abrir una sesión interactiva de la shell preferida del usuario (Si necesita ejecutar un script shell, use un intérprete específico como /bin/sh)
  • TERM, TERMINFOy TERMCAP, si vas a usar secuencias de escape específicas de terminal
  • TMPDIR, si vas a crear archivos temporales
  • HOME, para localizar archivos de configuración
  • PAGER, si desea publicar automáticamente la salida de página
  • LINESy COLUMNS, para la salida que depende del tamaño de la pantalla (p. ej. tablas)

Leer las variables de entorno de .enven su caso. Si un comando define variables de entorno que es poco probable que cambien mientras el usuario esté trabajando en un directorio en particular, entonces también debería leerlos de un lugareño .envarchivo para que los usuarios puedan configurarlo de forma diferente para diferentes proyectos sin tener que especificarlos cada vez. Muchas lenguas tienen bibliotecas para la lectura .envarchivos (Rust, Node, Ruby).

No usar .envcomo sustituto de un archivo de configuración adecuado. .envLos archivos tienen muchas limitaciones:

  • A .envfile no se almacena comúnmente en el control de la fuente
  • (Por lo tanto, cualquier configuración almacenada en ella no tiene antecedentes)
  • Sólo tiene un tipo de datos: cadena
  • Se presta a estar mal organizado
  • Hace que las cuestiones de codificación sean fáciles de introducir
  • A menudo contiene credenciales sensibles y material clave que se almacenaría mejor de forma más segura

Si parece que estas limitaciones obstaculizarán la usabilidad o la seguridad, entonces un archivo de configuración dedicado podría ser más apropiado.

No lea secretos de las variables de entorno. Si bien las variables ambientales pueden ser convenientes para almacenar secretos, han demostrado ser demasiado propensas a fugas:

  • Las variables de entorno exportados se envían a cada proceso, y desde allí pueden filtrarse fácilmente a los registros o ser exfiltradas
  • Suscciones de conchas como curl -H "Authorization: Bearer $BEARER_TOKEN"se filtrará al estado de proceso legible a nivel mundial. (cURL ofrece la -H @filenamealternativa para leer encabezados sensibles de un archivo.)
  • Las variables de entorno de contenedores de la moqueta pueden ser vistas por cualquier persona con acceso Docker daemon a través de docker inspect
  • Las variables de medio ambiente en las unidades sistemadas son legibles a nivel mundial a través systemctl show

Los secretos solo deben ser aceptados a través de archivos de credencial, tuberías, AF_UNIXenchumas, servicios de gestión secreta, u otro mecanismo IPC.

Nombrando

El nombre de su programa es particularmente importante en el CLI: sus usuarios lo escribirán todo el tiempo, y tiene que ser fácil de recordar y escribir.

Que sea una palabra simple y memorable. Pero no demasiado genérico, o pisará los dedos de los pies de otros comandos y confundir a los usuarios. Por ejemplo, tanto ImageMagick como Windows usaron el comando convert.

Usa sólo letras minúsculas, y se desvanece si realmente necesitas. curles un buen nombre, DownloadURLNo lo es.

Mantenlo corto. Los usuarios lo escribirán todo el tiempo. No lo haga demasiado corto: los comandos más cortos están mejor reservados para las utilidades comunes utilizadas todo el tiempo, tales como cd, ls, ps.

Haz que sea fácil de escribir. Algunas palabras fluen a través del teclado QWERTY mucho más fácilmente que otras, y no sólo se trata de brevedad. plumpuede ser bajito, pero es una danza incómoda y angular. applete suba con la doble letra. orangees más largo que ambos, pero fluye mucho mejor.

Lea además: Los Poéticos de los nombres de comandos CLI

Distribución

Si es posible, distribuya como un solo binario. Si su idioma no compila a los ejecutables binarios de serie, a ver si tiene algo como PyInstaller. Si realmente no puedes distribuir como un solo binario, usa el instalador de paquetes nativos de la plataforma para que no estés esparciendo cosas en el disco que no se puede quitar fácilmente. Pisa ligeramente en el ordenador del usuario.

Si estás haciendo una herramienta específica del idioma, como un código linter, entonces esta regla no aplica-it-s seguro asumir que el usuario tiene un intérprete para ese idioma instalado en su computadora.

Haz que sea fácil desinstalar. Si necesita instrucciones, ponlas en la parte inferior de las instrucciones de instalación.uno de los momentos más comunes que la gente quiere desinstalar el software es justo después de instalarlo.

Análisis

Las métricas de uso pueden ser útiles para entender cómo los usuarios están usando su programa, cómo hacerlo mejor y dónde enfocar el esfuerzo. Pero, a diferencia de los sitios web, los usuarios de la línea de mando esperan tener el control de su entorno, y es sorprendente cuando los programas hacen las cosas en segundo plano sin decírselo.

No llame al teléfono al uso doméstico o datos de choque sin consentimiento. Los usuarios se enterarán, y se enojarán. Sé muy explícito sobre lo que recaudas, por qué lo recoges, lo anónimo que es y cómo lo anonizas, y cuánto tiempo lo conservas.

Idealmente, pregunte a los usuarios si quieren aportar datos (opt-in). Si usted elige hacerlo por defecto (opt-out), entonces claramente dile a los usuarios sobre ello en su sitio web o primero ejecute, y haga que sea fácil de desactivar.

Ejemplos de proyectos que recopilan estadísticas de uso:

Considere alternativas para recolectar análisis.

  • Instrumental tus documentos web. Si quieres saber cómo la gente está usando tu herramienta CLI, haz un conjunto de documentos alrededor de los casos de uso que te gustaría entender mejor, y ver cómo se desempeñan con el tiempo. Mira lo que la gente busca dentro de tus documentos.
  • Instrumental sus descargas. Esto puede ser una métrica aproximada para entender el uso y qué sistemas operativos están ejecutando sus usuarios.
  • Habla con tus usuarios. Alcanza y pregámale a la gente cómo están usando su herramienta. Anime la retroalimentación y las solicitudes de características en sus documentos y repos, y trate de extraer más contexto de aquellos que envían retroalimentación.

Lea además: Metrics de código abierto

Lectura más

Convenciones de

Scroll al inicio