# Regla: Estilo de Código

El código se lee muchas más veces de las que se escribe. Estas reglas maximizan
la legibilidad y reducen la carga cognitiva de quien mantiene el código después.
Aplican a todos los lenguajes del stack salvo indicación contraria.

---

## Nombres descriptivos

- Los nombres son documentación. Un nombre que requiere un comentario para
  entenderse es un nombre malo — renombrar.
- Variables, funciones y clases: nombrar por lo que SON o lo que HACEN,
  no por su tipo ni su implementación.
  - Mal: `d`, `tmp`, `data`, `obj`, `flag`, `result`
  - Bien: `fecha_entrega`, `usuario_autenticado`, `calcular_impuesto()`
- Booleanos: prefijo `es_`, `tiene_`, `puede_`, `esta_`.
  - Mal: `activo`, `valido`, `habilitado`
  - Bien: `es_activo`, `tiene_permisos`, `puede_editar`
- Funciones: verbo + sustantivo. Describe la acción y el objeto.
  - Mal: `proceso()`, `handler()`, `manage()`
  - Bien: `procesar_pago()`, `manejar_solicitud_reembolso()`
- Colecciones: plural del elemento.
  - Mal: `lista`, `items`, `data`
  - Bien: `facturas`, `usuarios_activos`, `errores_validacion`
- No abreviaciones salvo las universalmente conocidas (`id`, `url`, `http`, `api`).
  Siempre en el contexto del proyecto — si hay duda, escribir completo.

---

## Funciones cortas — límite estricto de 30 líneas

- Una función hace UNA sola cosa. Si se necesita "y" para describir lo que hace,
  es candidata a dividirse.
- Límite de 30 líneas de código efectivo (sin contar comentarios, líneas en blanco
  ni firmas de función).
- Si una función supera 30 líneas: extraer subfunciones con nombres descriptivos.
  El cuerpo de la función original queda como un sumario legible de pasos.
- Parámetros: máximo 4. Si se necesitan más, agrupar en un objeto/dataclass.
- Complejidad ciclomática máxima: 5. Más de 5 ramas → refactorizar.

---

## Un solo nivel de abstracción por función

- Cada función opera en un único nivel de abstracción. No mezclar operaciones
  de alto nivel (lógica de negocio) con detalles de bajo nivel (parsing, formateo).

  Mal — mezcla niveles:
  ```python
  def procesar_pedido(pedido_id):
      pedido = db.execute("SELECT * FROM pedidos WHERE id = %s", (pedido_id,))
      if pedido["estatus"] == "pendiente":
          total = sum(item["precio"] * item["cantidad"] for item in pedido["items"])
          db.execute("UPDATE pedidos SET total = %s WHERE id = %s", (total, pedido_id))
  ```

  Bien — nivel uniforme:
  ```python
  def procesar_pedido(pedido_id):
      pedido = obtener_pedido(pedido_id)
      if esta_pendiente(pedido):
          actualizar_total(pedido)
  ```

---

## Early return — evitar anidamiento profundo

- Validar precondiciones al inicio y retornar inmediatamente si no se cumplen.
  Nunca anidar la lógica principal dentro de múltiples `if`.
- Máximo 2 niveles de anidamiento dentro de una función (sin contar el cuerpo
  de la función en sí). Si se llega a 3: early return o extracción de función.

  Mal:
  ```python
  def crear_factura(usuario, items):
      if usuario:
          if items:
              if len(items) > 0:
                  # lógica principal aquí, muy adentro
  ```

  Bien:
  ```python
  def crear_factura(usuario, items):
      if not usuario:
          raise ValueError("Usuario requerido")
      if not items:
          raise ValueError("La factura debe tener al menos un ítem")
      # lógica principal al nivel superior
  ```

---

## Sin código muerto

- Eliminar código comentado antes de hacer merge. Si se necesita recuperar algo,
  existe git. El código comentado genera confusión sobre si está activo o no.
- Eliminar variables declaradas y nunca usadas.
- Eliminar imports no utilizados.
- Eliminar funciones que ya no tienen llamadores (verificar con búsqueda global).
- Eliminar flags de feature que ya no tienen sentido (limpiar deuda técnica).
- Los linters (flake8, ESLint, Pylance) deben pasar en CI sin warnings de código muerto.

---

## Principio DRY — no duplicar conocimiento

- DRY no es solo "no duplicar texto". Es no duplicar conocimiento. Si una regla
  de negocio, una validación, una query o una transformación existe en un lugar,
  no debe existir en otro. Cuando el conocimiento cambia, debe cambiar en un solo sitio.
- Antes de crear una función, clase o módulo nuevo: buscar si ya existe algo que
  haga lo mismo con Grep o Glob. Si existe, reutilizar o extender — no duplicar.
- Señales de violación DRY que deben corregirse:
  - Misma query SQL en 2+ lugares → extraer a un método del repositorio
  - Misma validación de input en 2+ endpoints → extraer a un schema/validator compartido
  - Misma transformación de datos en 2+ puntos → extraer a una función helper
  - Misma constante definida en múltiples archivos → mover a un módulo de constantes
  - Mismo bloque try/except en 2+ funciones → extraer a un decorator o context manager
- Dos funciones que hacen lo mismo pero por razones de negocio distintas NO son
  violaciones DRY. DRY aplica cuando el conocimiento duplicado cambiaría junto:
  si un cambio en un lugar obliga a cambiar el otro, es duplicación.
- Tres líneas de código similares son mejor que una abstracción prematura. DRY no
  justifica crear helpers de una sola línea que se usan dos veces.

---

## Sin console.log / print en producción

- `console.log()`, `print()`, `console.debug()`, `System.out.println()` y
  equivalentes están prohibidos en código que se mergea a main.
- Usar el logger configurado del proyecto:
  - Python: `import logging; logger = logging.getLogger(__name__)`
  - TypeScript/Angular: servicio de logging centralizado o `LoggingService`
- Nivel de log apropiado: `DEBUG` para desarrollo, `INFO` para flujos importantes,
  `WARNING` para situaciones inesperadas recuperables, `ERROR` para fallos.
- Los logs de nivel DEBUG no aparecen en producción — configurar por entorno.
- CI debe fallar si encuentra `console.log` o `print(` fuera de archivos de test.

---

## Organización de imports

Python — orden PEP 8, separados por línea en blanco:
1. Standard library (`os`, `sys`, `datetime`, etc.)
2. Dependencias de terceros (`fastapi`, `sqlalchemy`, `pydantic`, etc.)
3. Módulos propios del proyecto (con rutas absolutas desde la raíz del proyecto)

TypeScript/Angular — orden ESLint import/order:
1. Angular core y common (`@angular/core`, `@angular/common`)
2. Angular material y otras librerías (`@angular/material/*`)
3. RxJS (`rxjs`, `rxjs/operators`)
4. Librerías de terceros
5. Módulos propios (paths con alias `@app/`, `@core/`, `@shared/`)

Reglas adicionales:
- Sin imports con wildcard (`from module import *`) salvo `__init__.py` explícito.
- Un import por línea en TypeScript.
- Usar paths absolutos en imports propios — nunca `../../../../../../modulo`.

---

## Constantes con SCREAMING_CASE

- Toda constante con valor literal que se usa en múltiples lugares:
  definir una sola vez con nombre en SCREAMING_CASE.
- Agrupa constantes relacionadas en un módulo o clase de constantes.
  ```python
  # constants.py
  MAX_INTENTOS_LOGIN = 5
  TIEMPO_EXPIRACION_TOKEN_MINUTOS = 60
  ROLES_ADMINISTRADORES = ["ADMIN", "SUPERADMIN"]
  ```
- En TypeScript, usar `const` con SCREAMING_CASE o `enum` con PascalCase.
- NUNCA magic numbers o magic strings dispersos en el código.
  Si aparece un literal numérico o string no trivial: extraerlo a constante.

---

## Reglas adicionales de legibilidad

- Longitud máxima de línea: 100 caracteres (Python), 120 caracteres (TypeScript).
- Un solo nivel de ternario. Ternarios anidados: prohibidos.
- No usar `else` después de `return` o `raise` — es redundante y añade anidamiento.
- Agrupar código relacionado. Separar grupos con una línea en blanco.
- Comentarios en español (idioma del proyecto). Gramática y ortografía correctas.
- Comentarios explican el POR QUÉ, no el QUÉ. El código explica el qué.

---

## Checklist de estilo antes de abrir PR

- [ ] Sin variables, imports o funciones sin usar
- [ ] Sin código comentado
- [ ] Sin console.log/print de debug
- [ ] Nombres descriptivos en todo el código nuevo
- [ ] Funciones <= 30 líneas
- [ ] Sin magic numbers ni magic strings
- [ ] Sin duplicación de lógica de negocio entre módulos (DRY)
- [ ] Linter y type-checker pasan sin warnings
