---
name: calidad-anti-patrones-universales
description: >
  Catálogo de 10 anti-patrones universales de calidad de código, nombrados con
  vocabulario común y ejemplos MAL/BIEN en Python y TypeScript. Cubre auditoría
  de reutilización, proliferación de parámetros, abstracciones con fuga, tipado
  por string, condicionales anidadas, variantes copy-paste, actualizaciones sin
  efecto, race conditions TOCTOU, operaciones demasiado amplias y estado
  redundante. Cargar desde revisor-codigo-swl o revisores especializados cuando
  el código bajo revisión presenta señales (>4 parámetros, magic strings en
  condiciones, if anidadas ≥3 niveles, queries en loops, dos funciones casi
  idénticas, mutaciones de estado sin guard). NO sustituye a los revisores —
  los enriquece con vocabulario nombrado para reportes consistentes.
version: "1.0.0"
herramientasPermitidas: [Read, Grep, Glob]
exclusiones:
  - "No cargar como sustituto de revisor-codigo-swl ni de los revisores especializados — este skill aporta vocabulario y ejemplos, los revisores ejecutan el análisis."
  - "No cargar para code review con foco en seguridad (OWASP, inyección, autenticación) — para eso cargar checklist-seguridad."
  - "No cargar para análisis de rendimiento (queries lentas, profiling) — eso corresponde a rendimiento-swl + performance-baseline."
  - "No cargar para refactor agresivo de código heredado — eso corresponde a legacy-code-rescue."
evolvable: true
---

# Habilidad: Catálogo de anti-patrones universales de calidad

Catálogo de 10 anti-patrones nombrados que aparecen cross-lenguaje. Cada entrada
incluye señal de detección, ejemplo MAL, ejemplo BIEN y vocabulario para el
reporte del revisor.

## Cuándo cargar

Desde `revisor-codigo-swl` o un revisor especializado (`revisor-typescript-swl`,
`revisor-react-swl`, `revisor-python-swl`, etc.) cuando el código bajo revisión
muestra al menos una de las señales:

- Función con ≥5 parámetros posicionales
- Condicionales anidadas con ≥3 niveles
- Magic strings repetidos en condiciones o switches
- Dos funciones que difieren solo en nombres de campos
- Acceso a propiedades de un ORM o cliente HTTP desde código de negocio
- Llamadas a BD dentro de un `for` (loops con `await` en cada iteración)
- Mutación de estado sin guard previo
- Función con verbo genérico (`process`, `handle`, `manage`) que afecta múltiples dominios

## Cuándo NO cargar

- Code review enfocado en seguridad → `checklist-seguridad`
- Profiling y queries lentas → `rendimiento-swl` + `performance-baseline`
- Refactor de código heredado → `legacy-code-rescue`
- Implementación de feature nueva → cargar el skill del stack (`fastapi-experto`, `react-experto`, etc.)

---

## Los 10 anti-patrones

### 1. Auditoría de reutilización (reuse audit)

Antes de aceptar código nuevo, buscar utilidades existentes que ya hagan lo mismo.

**MAL** — debounce hecho a mano cuando `utils/debounce.ts` ya existe:
```typescript
function debounce(fn: Function, ms: number) {
  let timer: ReturnType<typeof setTimeout>;
  return (...args: unknown[]) => {
    clearTimeout(timer);
    timer = setTimeout(() => fn(...args), ms);
  };
}
```

**BIEN** — importar la utilidad del proyecto:
```typescript
import { debounce } from '@/utils/debounce';
```

**Reporte**: "Reuse audit — `<archivo:línea>` reimplementa `<utilidad-existente>`. Importar en su lugar."

---

### 2. Proliferación de parámetros (parameter sprawl)

Una función con ≥5 parámetros posicionales no escala. Cada nueva necesidad agrega otro.

**MAL**:
```python
def crear_usuario(nombre, email, rol, equipo, activo, avatar_url, zona_horaria):
    ...
```

**BIEN** — objeto de parámetros con defaults:
```python
from dataclasses import dataclass

@dataclass
class CrearUsuarioParams:
    nombre: str
    email: str
    rol: Rol = Rol.MIEMBRO
    equipo: str | None = None
    activo: bool = True
    avatar_url: str | None = None
    zona_horaria: str = "America/Mexico_City"

def crear_usuario(params: CrearUsuarioParams) -> Usuario:
    ...
```

**Reporte**: "Parameter sprawl — `<función>` recibe N parámetros. Consolidar en dataclass/interface."

Señal adicional: parámetros booleanos mutuamente exclusivos (`activar_x`, `desactivar_y`) → enum o strategy pattern.

---

### 3. Abstracciones con fuga (leaky abstractions)

Exponer detalles internos obliga al llamador a conocerlos.

**MAL** — el caller recibe un objeto ORM:
```python
def listar_usuarios():
    return session.query(Usuario).filter(Usuario.activo == True).all()
```

**BIEN** — el caller recibe un DTO de dominio:
```python
def listar_usuarios_activos() -> list[UsuarioDTO]:
    filas = usuario_repo.find_activos()
    return [UsuarioDTO.from_row(f) for f in filas]
```

**Reporte**: "Leaky abstraction — `<función>` retorna objeto ORM/cliente; envolver en DTO."

---

### 4. Tipado por string (stringly-typed)

Magic strings esparcidos por el código en lugar de constantes o enums.

**MAL**:
```typescript
if (usuario.rol === 'admin') { ... }
if (usuario.rol === 'Admin') { ... }   // typo silencioso
if (pedido.estado === 'pendiente') { ... }
```

**BIEN** — enum tipado:
```typescript
enum Rol { Admin = 'admin', Miembro = 'miembro' }
enum EstadoPedido { Pendiente = 'pendiente', Confirmado = 'confirmado' }

if (usuario.rol === Rol.Admin) { ... }
```

**Reporte**: "Stringly-typed — `<archivo:línea>` compara contra string literal repetido. Extraer enum/constante."

---

### 5. Condicionales anidadas (nested conditionals)

`if/else` con ≥3 niveles o cadenas ternarias rompen la lectura lineal.

**MAL**:
```python
if usuario:
    if usuario.activo:
        if usuario.tiene_permiso("editar"):
            if recurso.disponible:
                return editar(usuario, recurso)
```

**BIEN** — early return con guard clauses:
```python
def editar_recurso(usuario, recurso):
    if not usuario or not usuario.activo:
        raise UsuarioInvalidoError
    if not usuario.tiene_permiso("editar"):
        raise PermisoDenegadoError
    if not recurso.disponible:
        raise RecursoNoDisponibleError
    return editar(usuario, recurso)
```

**Reporte**: "Nested conditionals — `<función>` tiene N niveles de anidamiento. Aplicar guard clauses con early return."

---

### 6. Variantes copy-paste (copy-paste variants)

Dos bloques de código casi idénticos que solo difieren en nombres de campos o constantes.

**MAL**:
```python
def calcular_iva(monto):
    return monto * 0.16

def calcular_ieps(monto):
    return monto * 0.08

def calcular_isr(monto):
    return monto * 0.30
```

**BIEN** — abstracción con tabla de tasas:
```python
TASAS = {"iva": 0.16, "ieps": 0.08, "isr": 0.30}

def calcular_impuesto(monto: Decimal, tipo: str) -> Decimal:
    return monto * TASAS[tipo]
```

**Reporte**: "Copy-paste variants — funciones `<a>`, `<b>` difieren solo en constantes. Consolidar."

Cuidado: NO consolidar si las funciones evolucionan independientemente por razones de negocio distintas (regla de tres).

---

### 7. Actualizaciones sin efecto (no-op updates)

Disparar `setState`, `UPDATE` o re-render sin verificar que el valor cambió.

**MAL** — re-render cada vez aunque `usuario` sea el mismo:
```typescript
useEffect(() => {
  setUsuarioActivo(usuario);
}, [usuario]);
```

**BIEN** — comparar antes de actualizar:
```typescript
useEffect(() => {
  if (usuario && usuario.id !== usuarioActivoActual?.id) {
    setUsuarioActivo(usuario);
  }
}, [usuario, usuarioActivoActual]);
```

**Reporte**: "No-op update — `<archivo:línea>` actualiza estado sin guard de cambio. Verificar si el valor difiere."

---

### 8. TOCTOU — Time-of-Check vs Time-of-Use

Entre la verificación y el uso, el estado puede cambiar. Race condition silenciosa.

**MAL**:
```python
if os.path.exists(ruta):
    with open(ruta) as f:  # archivo puede haber desaparecido aquí
        return f.read()
```

**BIEN** — intentar y manejar excepción:
```python
try:
    with open(ruta) as f:
        return f.read()
except FileNotFoundError:
    return None
```

**MAL** en BD — check-then-act sin transacción:
```python
saldo = obtener_saldo(cuenta_id)
if saldo >= monto:
    debitar(cuenta_id, monto)  # otro proceso pudo cambiar el saldo
```

**BIEN** — lock pesimista o transacción atómica:
```python
async with conn.transaction():
    saldo = await obtener_saldo_for_update(cuenta_id)  # SELECT ... FOR UPDATE
    if saldo < monto:
        raise SaldoInsuficienteError
    await debitar(cuenta_id, monto)
```

**Reporte**: "TOCTOU — `<archivo:línea>` verifica condición fuera de transacción/lock. Reordenar a try-catch o SELECT FOR UPDATE."

---

### 9. Operaciones demasiado amplias (overly broad operations)

Funciones con verbos genéricos (`process`, `handle`, `manage`) que tocan múltiples dominios.

**MAL**:
```typescript
async function procesarPedido(pedido: Pedido) {
  await validarCliente(pedido.clienteId);
  await debitarInventario(pedido.items);
  await cobrarTarjeta(pedido.pago);
  await enviarEmail(pedido.clienteId);
  await registrarAuditoria(pedido);
  await notificarAlmacen(pedido);
}
```

**BIEN** — fases nombradas, una responsabilidad por función:
```typescript
async function emitirPedido(pedido: Pedido) {
  const validado = await validarPedido(pedido);
  const cobrado = await procesarCobro(validado);
  const confirmado = await confirmarPedido(cobrado);
  await notificarParticipantes(confirmado);
  return confirmado;
}
```

**Reporte**: "Overly broad operation — `<función>` orquesta N dominios distintos. Dividir por fase o extraer use cases."

---

### 10. Estado redundante (redundant state)

Mantener estado derivable de otro estado introduce drift garantizado.

**MAL**:
```typescript
const [items, setItems] = useState<Item[]>([]);
const [total, setTotal] = useState(0);  // derivable de items
const [vacio, setVacio] = useState(true);  // derivable de items.length
```

**BIEN** — derivar con `useMemo`:
```typescript
const [items, setItems] = useState<Item[]>([]);
const total = useMemo(() => items.reduce((s, i) => s + i.precio, 0), [items]);
const vacio = items.length === 0;
```

**Reporte**: "Redundant state — `<componente>` mantiene N campos derivables de uno solo. Computar con `useMemo` o getter."

---

## Formato de reporte sugerido

Cuando un revisor detecta uno o más anti-patrones, integrarlo en su reporte
estándar con esta forma:

```markdown
### Anti-patrones detectados

| # | Patrón | Archivo:línea | Severidad | Remediación |
|---|---|---|---|---|
| 1 | Parameter sprawl | usuarios/service.py:42 | P1 | Extraer a `CrearUsuarioParams` |
| 2 | Stringly-typed | pedidos/handler.ts:88 | P2 | Crear `enum EstadoPedido` |
| 3 | TOCTOU | inventario/repo.py:120 | P0 | Envolver en `SELECT FOR UPDATE` |
```

Mapeo a severidades estándar de revisor-codigo-swl:
- **P0** (mata credibilidad): TOCTOU sin lock cuando hay concurrencia real
- **P1** (arreglar antes de merge): parameter sprawl >6, leaky abstraction cross-capa
- **P2** (pulir): stringly-typed con 2-3 usos, no-op updates cosméticos

## Lo que esta skill NO hace

- No reemplaza al revisor — el revisor ejecuta el análisis y decide.
- No verifica seguridad (eso es `checklist-seguridad`).
- No mide rendimiento (eso es `rendimiento-swl`).
- No corrige código — solo nombra el patrón y propone forma idiomática.

## Origen

Adaptación curada en es-MX de `reference/code-quality-universal.md` del repo
`anthropic-skills/code-review-skill` analizado en `temp/code-review-skill-main/`
(sesión 2026-05-24). Los 10 anti-patrones del catálogo original se tradujeron
y se ajustaron al stack Python + TypeScript predominante en proyectos SWL.
Material original bajo licencia compatible; adaptación con vocabulario
es-MX y ejemplos contextualizados.
