Principios para diseñar interfaces de línea de comandos intuitivas, consistentes y productivas que los desarrolladores disfruten usar.
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.
| Principio | Descripción | Implementación |
|---|---|---|
| Convenciones Unix | Seguir estándares establecidos | -v/--verbose, exit codes, pipes |
| Feedback inmediato | Comunicar estado y progreso | Progress bars, spinners, colores |
| Descubribilidad | Fácil de aprender y explorar | --help útil, sugerencias de comandos |
| Composabilidad | Compatible con pipes y scripts | Output JSON, stdin/stdout |
| Idempotencia | Resultados consistentes | create --if-not-exists |
| Graceful degradation | Funcionar en entornos limitados | Detectar TTY, fallbacks sin color |
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()# 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'?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
@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...")# 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| Lenguaje | Framework | Fortalezas |
|---|---|---|
| Python | Click | Decoradores, tipos, testing |
| Python | Typer | Type hints, async support |
| Node.js | Commander.js | Ligero, flexible |
| Node.js | oclif | Enterprise, plugins |
| Go | Cobra | Performance, distribución |
| Rust | clap | Type safety, performance |
| Ruby | Thor | DSL expresivo |
# ❌ 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.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.
Disciplina enfocada en optimizar la productividad, satisfacción y efectividad de los desarrolladores mediante herramientas, procesos y entornos bien diseñados.
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.
Principios y prácticas para diseñar interfaces de programación claras, consistentes y evolucionables que faciliten la integración entre sistemas.
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.