# Guía de estilo — STP ## Nomenclatura: camelCase sin excepciones Todo identificador del proyecto usa camelCase. No se usa guión bajo (`_`) ni guión (`-`) en nombres de variables, funciones o archivos Bash. | Tipo | Correcto | Incorrecto | |------|----------|------------| | Variable local | `packageName` | `package_name`, `pkg` | | Variable exportada | `stpRoot`, `verbose` | `STP_ROOT`, `VERBOSE` | | Constante (`readonly`) | `readonly packagesConfig` | `readonly PACKAGES_CONFIG` | | Función | `installAptPackages()` | `install_apt_packages()` | | Función privada | `log::emit` | `log::_emit`, `_emit` | | Archivo Bash | `encryptSsh.sh` | `encrypt-ssh.sh`, `encrypt_ssh.sh` | Los nombres de archivos YAML (`packages.yaml`, `audio.yaml`) son palabras simples y no requieren separador. --- ## Clean Code — Robert C. Martin ### Una función, una responsabilidad Cada función hace exactamente una cosa. Un bloque de código que necesita un comentario para explicarse debe convertirse en una función con un nombre descriptivo. ```bash # MAL — lógica mezclada con comentario explicativo if apt-cache show age &>/dev/null 2>&1; then sudo apt-get install -y age # instala desde apt si está disponible else # descarga binario de GitHub... fi # BIEN — la intención es legible sin comentarios if ageIsAvailableInApt; then installAgeFromApt else installAgeFromGithub fi ``` ### Nombres completos, sin abreviaciones ```bash # MAL for pkg in "${packages[@]}"; do ... for svc in "${services[@]}"; do ... # BIEN for packageName in "${packages[@]}"; do ... for serviceName in "${services[@]}"; do ... ``` Palabras prohibidas como nombre de variable: `pkg`, `svc`, `src`, `dest`, `dir`, `tmp`, `cfg`, `val`, `ret`, `f`, `i` (salvo índices numéricos en bucles simples). ### Predicados como preguntas Las funciones booleanas se nombran como preguntas que responden verdadero o falso: ```bash pipewireIsEnabled() # ¿PipeWire está habilitado en la config? isPpaAlreadyAdded() # ¿el PPA ya fue registrado en sources.list? dotfilesDirectoryIsEmpty() # ¿no hay dotfiles para desplegar? ``` ### Comentarios solo para el PORQUÉ El código expresa el QUÉ. Solo se agrega un comentario cuando el PORQUÉ no es evidente: una restricción externa, una solución provisional, un comportamiento sorpresivo. ```bash # MAL — el comentario dice lo mismo que el código # Verifica si el PPA ya está en sources.list.d isPpaAlreadyAdded "$ppaAddress" && continue # BIEN — el código habla por sí mismo; el comentario solo si hay un "porqué" no obvio ``` --- ## Código funcional sin modo simulación No existe `--dry-run`. El sistema es **idempotente**: verifica el estado actual antes de actuar y omite lo que ya está configurado. ```bash # Antes de instalar un paquete util::isAptInstalled "$packageName" && continue # Antes de agregar un PPA isPpaAlreadyAdded "$ppaAddress" && continue # Antes de instalar una clave SSH [[ -f "$destination" ]] && { log::warn "Ya existe: $keyFilename"; return 1; } ``` Ejecutar el STP dos veces produce exactamente el mismo resultado que ejecutarlo una vez. --- ## Agregar una nueva configuración al sistema La forma principal de agregar algo al STP es agregar una entrada a `config/registry.yaml`. No se necesita crear un módulo nuevo para la mayoría de los casos. ```yaml # Basta con agregar una línea a la lista: - id: neovim type: apt # La próxima ejecución de stp.sh la detecta y aplica ``` Tipos disponibles en el registro: `ppa`, `apt`, `snap`, `flatpak`, `dotfile`, `service`, `pipewire`, `video`. Solo creá un módulo nuevo cuando la configuración requiera pasos que ningún tipo del registro puede manejar (compilación desde fuente, instaladores externos, configuración interactiva, etc.). --- ## Estructura de un módulo ```bash #!/usr/bin/env bash set -euo pipefail source "$stpRoot/lib/log.sh" source "$stpRoot/lib/utils.sh" source "$stpRoot/lib/yaml.sh" # solo si el módulo lee YAML readonly nombreConfig="$stpRoot/config/nombre.yaml" # Funciones auxiliares específicas (las más pequeñas y concretas) helperEspecifico() { ... } # Funciones principales que usan las auxiliares hacerAlgo() { log::info "Descripción breve..." helperEspecifico log::ok "Completado" } # Verificación inicial: salir si no hay configuración if [[ ! -f "$nombreConfig" ]]; then log::info "Sin configuración para este módulo, salteando" exit 0 fi # Punto de entrada al final del archivo hacerAlgo ```