# 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
```
