Jonatan Matajonmatum.com
conceptosnotasexperimentosensayos
© 2026 Jonatan Mata. All rights reserved.v2.1.1
Conceptos

Diseño de CLIs

Principios para diseñar interfaces de línea de comandos intuitivas, consistentes y productivas que los desarrolladores disfruten usar.

evergreen#cli#design#terminal#developer-experience#ux#tooling

¿Qué es?

El diseño de CLI (Command Line Interface) es el arte de crear herramientas de línea de comandos que los desarrolladores usan con placer y eficiencia. Un CLI bien diseñado sigue convenciones Unix establecidas, proporciona feedback claro y es descubrible sin leer documentación extensa.

A diferencia de las interfaces gráficas, los CLIs priorizan la velocidad, la composabilidad y la automatización. Son la interfaz preferida para desarrolladores, scripts de CI/CD y tareas de administración de sistemas porque permiten operaciones rápidas y repetibles.

Los mejores CLIs combinan potencia con simplicidad: ofrecen funcionalidad avanzada a través de flags y subcomandos, pero mantienen casos de uso comunes simples y directos.

Principios fundamentales

PrincipioDescripciónImplementación
Convenciones UnixSeguir estándares establecidos-v/--verbose, exit codes, pipes
Feedback inmediatoComunicar estado y progresoProgress bars, spinners, colores
DescubribilidadFácil de aprender y explorar--help útil, sugerencias de comandos
ComposabilidadCompatible con pipes y scriptsOutput JSON, stdin/stdout
IdempotenciaResultados consistentescreate --if-not-exists
Graceful degradationFuncionar en entornos limitadosDetectar TTY, fallbacks sin color

Implementación con Click (Python)

import click
from typing import Optional
 
@click.group()
@click.version_option()
@click.option('--verbose', '-v', is_flag=True, help='Enable verbose output')
@click.pass_context
def cli(ctx: click.Context, verbose: bool) -> None:
    """Modern CLI tool for project management."""
    ctx.ensure_object(dict)
    ctx.obj['verbose'] = verbose
 
@cli.command()
@click.argument('name')
@click.option('--template', '-t', 
              type=click.Choice(['basic', 'advanced']), 
              default='basic',
              help='Project template to use')
@click.option('--force', is_flag=True, 
              help='Overwrite existing project')
@click.pass_context
def create(ctx: click.Context, name: str, template: str, force: bool) -> None:
    """Create a new project."""
    if ctx.obj['verbose']:
        click.echo(f"Creating project '{name}' with template '{template}'")
    
    # Validación con mensajes claros
    if not force and project_exists(name):
        click.echo(f"Error: Project '{name}' already exists. Use --force to overwrite.", err=True)
        ctx.exit(1)
    
    # Progress feedback
    with click.progressbar(range(100), label='Setting up project') as bar:
        for i in bar:
            setup_step(i)
    
    click.echo(f"✅ Project '{name}' created successfully!")
 
@cli.command()
@click.option('--format', type=click.Choice(['table', 'json']), 
              default='table', help='Output format')
def list(format: str) -> None:
    """List all projects."""
    projects = get_projects()
    
    if format == 'json':
        click.echo(json.dumps(projects))
    else:
        # Tabla formateada para humanos
        for project in projects:
            click.echo(f"{project['name']:<20} {project['status']}")
 
if __name__ == '__main__':
    cli()

Patrones de diseño de ayuda

Ayuda contextual

# Ayuda general
$ myapp --help
 
# Ayuda específica de subcomando
$ myapp create --help
 
# Sugerencias ante errores
$ myapp creat project1
Error: No such command 'creat'. Did you mean 'create'?

Estructura de mensajes de ayuda

Usage: myapp [OPTIONS] COMMAND [ARGS]...

  Modern CLI tool for project management.

Options:
  -v, --verbose    Enable verbose output
  --version        Show version and exit
  --help           Show this message and exit

Commands:
  create  Create a new project
  list    List all projects
  deploy  Deploy project to environment

Prompts interactivos

@cli.command()
def setup() -> None:
    """Interactive setup wizard."""
    # Prompt con validación
    name = click.prompt('Project name', 
                       type=str,
                       value_proc=lambda x: x.strip().lower())
    
    # Confirmación con default
    use_git = click.confirm('Initialize git repository?', default=True)
    
    # Selección múltiple
    template = click.prompt(
        'Choose template',
        type=click.Choice(['basic', 'web', 'api']),
        show_choices=True
    )
    
    # Password oculto
    if click.confirm('Set up authentication?'):
        token = click.prompt('API token', hide_input=True)
    
    click.echo(f"Setting up '{name}' with {template} template...")

Completado de shell

# Bash completion
eval "$(_MYAPP_COMPLETE=bash_source myapp)"
 
# Zsh completion  
eval "$(_MYAPP_COMPLETE=zsh_source myapp)"
 
# Fish completion
eval (env _MYAPP_COMPLETE=fish_source myapp)

Implementación en Click:

# Autocompletado personalizado
def complete_projects(ctx, param, incomplete):
    """Autocompletar nombres de proyectos existentes."""
    projects = get_projects()
    return [p['name'] for p in projects if p['name'].startswith(incomplete)]
 
@click.argument('project', autocompletion=complete_projects)
def deploy(project: str) -> None:
    """Deploy project."""
    pass

Frameworks por lenguaje

LenguajeFrameworkFortalezas
PythonClickDecoradores, tipos, testing
PythonTyperType hints, async support
Node.jsCommander.jsLigero, flexible
Node.jsoclifEnterprise, plugins
GoCobraPerformance, distribución
RustclapType safety, performance
RubyThorDSL expresivo

Anti-patrones comunes

# ❌ Flags inconsistentes
myapp --verbose create
myapp deploy -v  # Debería ser --verbose también
 
# ❌ Output no parseable
myapp list
Project: web-app (status: running, created: yesterday)
 
# ✅ Output estructurado
myapp list --json
{"projects": [{"name": "web-app", "status": "running", "created": "2026-03-18"}]}
 
# ❌ Mensajes de error vagos
Error: Something went wrong
 
# ✅ Mensajes de error accionables
Error: Project 'web-app' not found. Run 'myapp list' to see available projects.

Arquitectura de CLI escalable

Loading diagram...

¿Por qué importa?

Un CLI bien diseñado es la diferencia entre una herramienta que se adopta ampliamente y una que se abandona. Los desarrolladores senior evalúan CLIs en segundos: si no siguen convenciones Unix, si los mensajes de error son vagos, o si no hay autocompletado, buscan alternativas.

La experiencia de desarrollador se define por estos detalles: tiempo de respuesta, claridad de mensajes, y capacidad de automatización. Un CLI excelente reduce la fricción cognitiva y permite flujos de trabajo más eficientes.

En organizaciones grandes, los CLIs internos mal diseñados generan tickets de soporte constantes y reducen la productividad del equipo. Invertir en buen diseño de CLI es invertir en la velocidad de desarrollo del equipo.

Referencias

  • Command Line Interface Guidelines — Guía completa de mejores prácticas para CLIs.
  • GitHub - tj/commander.js: node.js command-line interfaces made easy — TJ Holowaychuk, 2024. Framework popular para CLIs en Node.js.
  • Welcome to Click — Click Documentation (8.3.x) — Pallets Team, 2024. Framework Python para CLIs con decoradores.
  • clap - Rust — Rust community, 2024. Parser de argumentos para Rust con derive macros.
  • GitHub - spf13/cobra: A Commander for modern Go CLI interactions — Steve Francia, 2024. Framework CLI usado por kubectl, hugo y otros.
  • GitHub - oclif/oclif: CLI for generating, building, and releasing oclif CLIs. Built by Salesforce. — Salesforce, 2024. Framework enterprise para CLIs con sistema de plugins.
  • argparse — Parser for command-line options, arguments and subcommands — Python 3.14.3 documentation — Python Software Foundation, 2024. Biblioteca estándar de Python para parsing de argumentos.

Contenido relacionado

  • Experiencia del Desarrollador

    Disciplina enfocada en optimizar la productividad, satisfacción y efectividad de los desarrolladores mediante herramientas, procesos y entornos bien diseñados.

  • Diseño de SDKs

    Principios para diseñar kits de desarrollo que sean intuitivos, consistentes y faciliten la integración de servicios en múltiples lenguajes de programación.

  • Diseño de APIs

    Principios y prácticas para diseñar interfaces de programación claras, consistentes y evolucionables que faciliten la integración entre sistemas.

  • Terminal UI

    Sistema de diseno estilo terminal con temas Matrix y TRON, integración del código Konami y soporte para micro frontends. Publicado en npm como @jonmatum/terminal-ui.

Conceptos